Split errors (#158)
* add migration for splitting errors * fix type from u32 to u64 * update entities to match migrations * no migration needed. these are only in stats * add user_error_response to influx * only if detailed * set error_response and user_error_response * 0 cost error responses * only 33 migrations now * put macros back * get the stat buffer sender to the TestApp helper * fixes
This commit is contained in:
parent
aee220b7ad
commit
eb7b98fdbe
|
@ -1678,7 +1678,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "entities"
|
name = "entities"
|
||||||
version = "0.32.0"
|
version = "0.33.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethers",
|
"ethers",
|
||||||
"sea-orm",
|
"sea-orm",
|
||||||
|
@ -3354,7 +3354,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "migration"
|
name = "migration"
|
||||||
version = "0.32.0"
|
version = "0.33.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sea-orm-migration",
|
"sea-orm-migration",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -133,6 +133,7 @@ cargo install sea-orm-cli
|
||||||
3. `sea-orm-cli generate entity -u mysql://root:dev_web3_proxy@127.0.0.1:13306/dev_web3_proxy -o entities/src --with-serde both`
|
3. `sea-orm-cli generate entity -u mysql://root:dev_web3_proxy@127.0.0.1:13306/dev_web3_proxy -o entities/src --with-serde both`
|
||||||
- Be careful when adding the `--tables THE,MODIFIED,TABLES` flag. It will delete relationships if they aren't listed
|
- Be careful when adding the `--tables THE,MODIFIED,TABLES` flag. It will delete relationships if they aren't listed
|
||||||
4. After running the above, you will need to manually fix some things
|
4. After running the above, you will need to manually fix some things
|
||||||
|
- Add any derives that got removed (like `Default`)
|
||||||
- `Vec<u8>` -> `sea_orm::prelude::Uuid` (Related: <https://github.com/SeaQL/sea-query/issues/375>)
|
- `Vec<u8>` -> `sea_orm::prelude::Uuid` (Related: <https://github.com/SeaQL/sea-query/issues/375>)
|
||||||
- `i8` -> `bool` (Related: <https://github.com/SeaQL/sea-orm/issues/924>)
|
- `i8` -> `bool` (Related: <https://github.com/SeaQL/sea-orm/issues/924>)
|
||||||
- add all the tables back into `mod.rs`
|
- add all the tables back into `mod.rs`
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "entities"
|
name = "entities"
|
||||||
version = "0.32.0"
|
version = "0.33.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -10,7 +10,9 @@ pub struct Model {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub caller: u64,
|
pub caller: u64,
|
||||||
pub imitating_user: Option<u64>,
|
pub imitating_user: Option<u64>,
|
||||||
|
#[sea_orm(column_type = "Text")]
|
||||||
pub endpoint: String,
|
pub endpoint: String,
|
||||||
|
#[sea_orm(column_type = "Text")]
|
||||||
pub payload: String,
|
pub payload: String,
|
||||||
pub timestamp: DateTimeUtc,
|
pub timestamp: DateTimeUtc,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use crate::serialization;
|
use crate::serialization;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
#[sea_orm(unique)]
|
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(16)))", unique)]
|
||||||
#[serde(serialize_with = "serialization::uuid_as_ulid")]
|
#[serde(serialize_with = "serialization::uuid_as_ulid")]
|
||||||
pub bearer_token: Uuid,
|
pub bearer_token: Uuid,
|
||||||
pub user_id: u64,
|
pub user_id: u64,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use crate::serialization;
|
use crate::serialization;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
#[sea_orm(unique)]
|
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(16)))", unique)]
|
||||||
#[serde(serialize_with = "serialization::uuid_as_ulid")]
|
#[serde(serialize_with = "serialization::uuid_as_ulid")]
|
||||||
pub nonce: Uuid,
|
pub nonce: Uuid,
|
||||||
#[sea_orm(column_type = "Text")]
|
#[sea_orm(column_type = "Text")]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
pub use super::admin::Entity as Admin;
|
pub use super::admin::Entity as Admin;
|
||||||
pub use super::admin_increase_balance_receipt::Entity as AdminIncreaseBalanceReceipt;
|
pub use super::admin_increase_balance_receipt::Entity as AdminIncreaseBalanceReceipt;
|
||||||
|
@ -14,5 +14,6 @@ pub use super::rpc_accounting::Entity as RpcAccounting;
|
||||||
pub use super::rpc_accounting_v2::Entity as RpcAccountingV2;
|
pub use super::rpc_accounting_v2::Entity as RpcAccountingV2;
|
||||||
pub use super::rpc_key::Entity as RpcKey;
|
pub use super::rpc_key::Entity as RpcKey;
|
||||||
pub use super::secondary_user::Entity as SecondaryUser;
|
pub use super::secondary_user::Entity as SecondaryUser;
|
||||||
|
pub use super::stripe_increase_balance_receipt::Entity as StripeIncreaseBalanceReceipt;
|
||||||
pub use super::user::Entity as User;
|
pub use super::user::Entity as User;
|
||||||
pub use super::user_tier::Entity as UserTier;
|
pub use super::user_tier::Entity as UserTier;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use super::sea_orm_active_enums::Method;
|
use super::sea_orm_active_enums::Method;
|
||||||
use crate::serialization;
|
use crate::serialization;
|
||||||
|
@ -13,6 +13,7 @@ pub struct Model {
|
||||||
pub rpc_key_id: u64,
|
pub rpc_key_id: u64,
|
||||||
pub timestamp: DateTimeUtc,
|
pub timestamp: DateTimeUtc,
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
|
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(20)))")]
|
||||||
#[serde(serialize_with = "serialization::vec_as_address")]
|
#[serde(serialize_with = "serialization::vec_as_address")]
|
||||||
pub to: Vec<u8>,
|
pub to: Vec<u8>,
|
||||||
#[sea_orm(column_type = "Text", nullable)]
|
#[sea_orm(column_type = "Text", nullable)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -19,6 +19,7 @@ pub struct Model {
|
||||||
pub cache_hits: u64,
|
pub cache_hits: u64,
|
||||||
pub sum_request_bytes: u64,
|
pub sum_request_bytes: u64,
|
||||||
pub min_request_bytes: u64,
|
pub min_request_bytes: u64,
|
||||||
|
#[sea_orm(column_type = "Double")]
|
||||||
pub mean_request_bytes: f64,
|
pub mean_request_bytes: f64,
|
||||||
pub p50_request_bytes: u64,
|
pub p50_request_bytes: u64,
|
||||||
pub p90_request_bytes: u64,
|
pub p90_request_bytes: u64,
|
||||||
|
@ -26,6 +27,7 @@ pub struct Model {
|
||||||
pub max_request_bytes: u64,
|
pub max_request_bytes: u64,
|
||||||
pub sum_response_millis: u64,
|
pub sum_response_millis: u64,
|
||||||
pub min_response_millis: u64,
|
pub min_response_millis: u64,
|
||||||
|
#[sea_orm(column_type = "Double")]
|
||||||
pub mean_response_millis: f64,
|
pub mean_response_millis: f64,
|
||||||
pub p50_response_millis: u64,
|
pub p50_response_millis: u64,
|
||||||
pub p90_response_millis: u64,
|
pub p90_response_millis: u64,
|
||||||
|
@ -33,6 +35,7 @@ pub struct Model {
|
||||||
pub max_response_millis: u64,
|
pub max_response_millis: u64,
|
||||||
pub sum_response_bytes: u64,
|
pub sum_response_bytes: u64,
|
||||||
pub min_response_bytes: u64,
|
pub min_response_bytes: u64,
|
||||||
|
#[sea_orm(column_type = "Double")]
|
||||||
pub mean_response_bytes: f64,
|
pub mean_response_bytes: f64,
|
||||||
pub p50_response_bytes: u64,
|
pub p50_response_bytes: u64,
|
||||||
pub p90_response_bytes: u64,
|
pub p90_response_bytes: u64,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use crate::serialization;
|
use crate::serialization;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
@ -10,7 +10,7 @@ pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub user_id: u64,
|
pub user_id: u64,
|
||||||
#[sea_orm(unique)]
|
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(16)))", unique)]
|
||||||
#[serde(serialize_with = "serialization::uuid_as_ulid")]
|
#[serde(serialize_with = "serialization::uuid_as_ulid")]
|
||||||
pub secret_key: Uuid,
|
pub secret_key: Uuid,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
@ -24,6 +24,7 @@ pub struct Model {
|
||||||
pub allowed_referers: Option<String>,
|
pub allowed_referers: Option<String>,
|
||||||
#[sea_orm(column_type = "Text", nullable)]
|
#[sea_orm(column_type = "Text", nullable)]
|
||||||
pub allowed_user_agents: Option<String>,
|
pub allowed_user_agents: Option<String>,
|
||||||
|
#[sea_orm(column_type = "Double")]
|
||||||
pub log_revert_chance: f64,
|
pub log_revert_chance: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use super::sea_orm_active_enums::Role;
|
use super::sea_orm_active_enums::Role;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||||
#[sea_orm(table_name = "stripe_increase_balance_receipt")]
|
#[sea_orm(table_name = "stripe_increase_balance_receipt")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub deposit_to_user_id: Option<u64>,
|
|
||||||
pub stripe_payment_intend_id: String,
|
pub stripe_payment_intend_id: String,
|
||||||
|
pub deposit_to_user_id: Option<u64>,
|
||||||
#[sea_orm(column_type = "Decimal(Some((20, 10)))")]
|
#[sea_orm(column_type = "Decimal(Some((20, 10)))")]
|
||||||
pub amount: Decimal,
|
pub amount: Decimal,
|
||||||
pub currency: String,
|
pub currency: String,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use crate::serialization;
|
use crate::serialization;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
#[sea_orm(unique)]
|
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(20)))", unique)]
|
||||||
#[serde(serialize_with = "serialization::vec_as_address")]
|
#[serde(serialize_with = "serialization::vec_as_address")]
|
||||||
pub address: Vec<u8>,
|
pub address: Vec<u8>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
@ -19,14 +19,28 @@ pub struct Model {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
#[sea_orm(has_many = "super::login::Entity")]
|
#[sea_orm(has_one = "super::admin::Entity")]
|
||||||
Login,
|
Admin,
|
||||||
#[sea_orm(has_many = "super::rpc_key::Entity")]
|
#[sea_orm(has_many = "super::admin_increase_balance_receipt::Entity")]
|
||||||
RpcKey,
|
AdminIncreaseBalanceReceipt,
|
||||||
|
#[sea_orm(has_one = "super::balance::Entity")]
|
||||||
|
Balance,
|
||||||
#[sea_orm(has_many = "super::increase_on_chain_balance_receipt::Entity")]
|
#[sea_orm(has_many = "super::increase_on_chain_balance_receipt::Entity")]
|
||||||
IncreaseOnChainBalanceReceipt,
|
IncreaseOnChainBalanceReceipt,
|
||||||
|
#[sea_orm(has_many = "super::login::Entity")]
|
||||||
|
Login,
|
||||||
|
#[sea_orm(has_many = "super::pending_login::Entity")]
|
||||||
|
PendingLogin,
|
||||||
|
#[sea_orm(has_one = "super::referee::Entity")]
|
||||||
|
Referee,
|
||||||
|
#[sea_orm(has_one = "super::referrer::Entity")]
|
||||||
|
Referrer,
|
||||||
|
#[sea_orm(has_many = "super::rpc_key::Entity")]
|
||||||
|
RpcKey,
|
||||||
#[sea_orm(has_many = "super::secondary_user::Entity")]
|
#[sea_orm(has_many = "super::secondary_user::Entity")]
|
||||||
SecondaryUser,
|
SecondaryUser,
|
||||||
|
#[sea_orm(has_many = "super::stripe_increase_balance_receipt::Entity")]
|
||||||
|
StripeIncreaseBalanceReceipt,
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
belongs_to = "super::user_tier::Entity",
|
belongs_to = "super::user_tier::Entity",
|
||||||
from = "Column::UserTierId",
|
from = "Column::UserTierId",
|
||||||
|
@ -37,15 +51,21 @@ pub enum Relation {
|
||||||
UserTier,
|
UserTier,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::login::Entity> for Entity {
|
impl Related<super::admin::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Login.def()
|
Relation::Admin.def()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::rpc_key::Entity> for Entity {
|
impl Related<super::admin_increase_balance_receipt::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::RpcKey.def()
|
Relation::AdminIncreaseBalanceReceipt.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::balance::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Balance.def()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,12 +75,48 @@ impl Related<super::increase_on_chain_balance_receipt::Entity> for Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::login::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Login.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::pending_login::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::PendingLogin.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::referee::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Referee.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::referrer::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Referrer.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::rpc_key::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::RpcKey.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Related<super::secondary_user::Entity> for Entity {
|
impl Related<super::secondary_user::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::SecondaryUser.def()
|
Relation::SecondaryUser.def()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::stripe_increase_balance_receipt::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::StripeIncreaseBalanceReceipt.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Related<super::user_tier::Entity> for Entity {
|
impl Related<super::user_tier::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::UserTier.def()
|
Relation::UserTier.def()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.7
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "migration"
|
name = "migration"
|
||||||
version = "0.32.0"
|
version = "0.33.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ mod m20230615_221201_handle_payment_uncles;
|
||||||
mod m20230618_230611_longer_payload;
|
mod m20230618_230611_longer_payload;
|
||||||
mod m20230619_172237_default_tracking;
|
mod m20230619_172237_default_tracking;
|
||||||
mod m20230622_104142_stripe_deposits;
|
mod m20230622_104142_stripe_deposits;
|
||||||
|
mod m20230705_214013_type_fixes;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
|
@ -73,6 +74,7 @@ impl MigratorTrait for Migrator {
|
||||||
Box::new(m20230618_230611_longer_payload::Migration),
|
Box::new(m20230618_230611_longer_payload::Migration),
|
||||||
Box::new(m20230619_172237_default_tracking::Migration),
|
Box::new(m20230619_172237_default_tracking::Migration),
|
||||||
Box::new(m20230622_104142_stripe_deposits::Migration),
|
Box::new(m20230622_104142_stripe_deposits::Migration),
|
||||||
|
Box::new(m20230705_214013_type_fixes::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
// Replace the sample below with your own migration scripts
|
||||||
|
manager
|
||||||
|
.alter_table(
|
||||||
|
Table::alter()
|
||||||
|
.table(IncreaseOnChainBalanceReceipt::Table)
|
||||||
|
.modify_column(
|
||||||
|
ColumnDef::new(IncreaseOnChainBalanceReceipt::LogIndex)
|
||||||
|
.big_unsigned()
|
||||||
|
.not_null(),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.alter_table(
|
||||||
|
Table::alter()
|
||||||
|
.table(IncreaseOnChainBalanceReceipt::Table)
|
||||||
|
.modify_column(
|
||||||
|
ColumnDef::new(IncreaseOnChainBalanceReceipt::LogIndex)
|
||||||
|
.big_integer()
|
||||||
|
.unsigned()
|
||||||
|
.not_null(),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Learn more at https://docs.rs/sea-query#iden
|
||||||
|
#[derive(Iden)]
|
||||||
|
enum IncreaseOnChainBalanceReceipt {
|
||||||
|
Table,
|
||||||
|
LogIndex,
|
||||||
|
}
|
|
@ -27,7 +27,6 @@ use anyhow::Context;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use deferred_rate_limiter::DeferredRateLimiter;
|
use deferred_rate_limiter::DeferredRateLimiter;
|
||||||
use derive_more::From;
|
|
||||||
use entities::user;
|
use entities::user;
|
||||||
use ethers::core::utils::keccak256;
|
use ethers::core::utils::keccak256;
|
||||||
use ethers::prelude::{Address, Bytes, Transaction, TxHash, H256, U64};
|
use ethers::prelude::{Address, Bytes, Transaction, TxHash, H256, U64};
|
||||||
|
@ -165,7 +164,6 @@ pub async fn flatten_handles<T>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// starting an app creates many tasks
|
/// starting an app creates many tasks
|
||||||
#[derive(From)]
|
|
||||||
pub struct Web3ProxyAppSpawn {
|
pub struct Web3ProxyAppSpawn {
|
||||||
/// the app. probably clone this to use in other groups of handles
|
/// the app. probably clone this to use in other groups of handles
|
||||||
pub app: Arc<Web3ProxyApp>,
|
pub app: Arc<Web3ProxyApp>,
|
||||||
|
@ -187,6 +185,7 @@ impl Web3ProxyApp {
|
||||||
top_config: TopConfig,
|
top_config: TopConfig,
|
||||||
num_workers: usize,
|
num_workers: usize,
|
||||||
shutdown_sender: broadcast::Sender<()>,
|
shutdown_sender: broadcast::Sender<()>,
|
||||||
|
flush_stat_buffer_receiver: broadcast::Receiver<()>
|
||||||
) -> anyhow::Result<Web3ProxyAppSpawn> {
|
) -> anyhow::Result<Web3ProxyAppSpawn> {
|
||||||
let stat_buffer_shutdown_receiver = shutdown_sender.subscribe();
|
let stat_buffer_shutdown_receiver = shutdown_sender.subscribe();
|
||||||
let mut background_shutdown_receiver = shutdown_sender.subscribe();
|
let mut background_shutdown_receiver = shutdown_sender.subscribe();
|
||||||
|
@ -399,6 +398,7 @@ impl Web3ProxyApp {
|
||||||
Some(user_balance_cache.clone()),
|
Some(user_balance_cache.clone()),
|
||||||
stat_buffer_shutdown_receiver,
|
stat_buffer_shutdown_receiver,
|
||||||
1,
|
1,
|
||||||
|
flush_stat_buffer_receiver,
|
||||||
)? {
|
)? {
|
||||||
// since the database entries are used for accounting, we want to be sure everything is saved before exiting
|
// since the database entries are used for accounting, we want to be sure everything is saved before exiting
|
||||||
important_background_handles.push(spawned_stat_buffer.background_handle);
|
important_background_handles.push(spawned_stat_buffer.background_handle);
|
||||||
|
@ -653,14 +653,13 @@ impl Web3ProxyApp {
|
||||||
important_background_handles.push(f);
|
important_background_handles.push(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((
|
Ok(Web3ProxyAppSpawn {
|
||||||
app,
|
app,
|
||||||
app_handles,
|
app_handles,
|
||||||
important_background_handles,
|
background_handles: important_background_handles,
|
||||||
new_top_config_sender,
|
new_top_config: new_top_config_sender,
|
||||||
consensus_connections_watcher,
|
ranked_rpcs: consensus_connections_watcher,
|
||||||
)
|
})
|
||||||
.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn apply_top_config(&self, new_top_config: TopConfig) -> Web3ProxyResult<()> {
|
pub async fn apply_top_config(&self, new_top_config: TopConfig) -> Web3ProxyResult<()> {
|
||||||
|
|
|
@ -135,8 +135,16 @@ impl ComputeUnit {
|
||||||
/// Compute cost per request
|
/// Compute cost per request
|
||||||
/// All methods cost the same
|
/// All methods cost the same
|
||||||
/// The number of bytes are based on input, and output bytes
|
/// The number of bytes are based on input, and output bytes
|
||||||
pub fn cost(&self, archive_request: bool, cache_hit: bool, usd_per_cu: Decimal) -> Decimal {
|
pub fn cost(
|
||||||
// TODO: server errors are free. need to split server and user errors
|
&self,
|
||||||
|
archive_request: bool,
|
||||||
|
cache_hit: bool,
|
||||||
|
error_response: bool,
|
||||||
|
usd_per_cu: Decimal,
|
||||||
|
) -> Decimal {
|
||||||
|
if error_response {
|
||||||
|
return 0.into();
|
||||||
|
}
|
||||||
|
|
||||||
let mut cost = self.0 * usd_per_cu;
|
let mut cost = self.0 * usd_per_cu;
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ use axum::headers::{Header, Origin, Referer, UserAgent};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use deferred_rate_limiter::DeferredRateLimitResult;
|
use deferred_rate_limiter::DeferredRateLimitResult;
|
||||||
|
use derivative::Derivative;
|
||||||
use derive_more::From;
|
use derive_more::From;
|
||||||
use entities::{balance, login, rpc_key, user, user_tier};
|
use entities::{balance, login, rpc_key, user, user_tier};
|
||||||
use ethers::types::{Bytes, U64};
|
use ethers::types::{Bytes, U64};
|
||||||
|
@ -309,7 +310,8 @@ impl KafkaDebugLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Derivative)]
|
||||||
|
#[derivative(Default)]
|
||||||
pub struct RequestMetadata {
|
pub struct RequestMetadata {
|
||||||
/// TODO: set archive_request during the new instead of after
|
/// TODO: set archive_request during the new instead of after
|
||||||
/// TODO: this is more complex than "requires a block older than X height". different types of data can be pruned differently
|
/// TODO: this is more complex than "requires a block older than X height". different types of data can be pruned differently
|
||||||
|
@ -329,7 +331,8 @@ pub struct RequestMetadata {
|
||||||
|
|
||||||
/// Instant that the request was received (or at least close to it)
|
/// Instant that the request was received (or at least close to it)
|
||||||
/// We use Instant and not timestamps to avoid problems with leap seconds and similar issues
|
/// We use Instant and not timestamps to avoid problems with leap seconds and similar issues
|
||||||
pub start_instant: tokio::time::Instant,
|
#[derivative(Default(value = "Instant::now()"))]
|
||||||
|
pub start_instant: Instant,
|
||||||
/// if this is empty, there was a cache_hit
|
/// if this is empty, there was a cache_hit
|
||||||
/// otherwise, it is populated with any rpc servers that were used by this request
|
/// otherwise, it is populated with any rpc servers that were used by this request
|
||||||
pub backend_requests: BackendRequests,
|
pub backend_requests: BackendRequests,
|
||||||
|
@ -348,6 +351,8 @@ pub struct RequestMetadata {
|
||||||
/// True if the response required querying a backup RPC
|
/// True if the response required querying a backup RPC
|
||||||
/// RPC aggregators that query multiple providers to compare response may use this header to ignore our response.
|
/// RPC aggregators that query multiple providers to compare response may use this header to ignore our response.
|
||||||
pub response_from_backup_rpc: AtomicBool,
|
pub response_from_backup_rpc: AtomicBool,
|
||||||
|
/// If the request is invalid or received a jsonrpc error response (excluding reverts)
|
||||||
|
pub user_error_response: AtomicBool,
|
||||||
|
|
||||||
/// ProxyMode::Debug logs requests and responses with Kafka
|
/// ProxyMode::Debug logs requests and responses with Kafka
|
||||||
/// TODO: maybe this shouldn't be determined by ProxyMode. A request param should probably enable this
|
/// TODO: maybe this shouldn't be determined by ProxyMode. A request param should probably enable this
|
||||||
|
@ -363,30 +368,6 @@ impl Default for Authorization {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// this is only implemented so that we can use `mem::take`. You probably shouldn't use this.
|
|
||||||
impl Default for RequestMetadata {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
archive_request: Default::default(),
|
|
||||||
authorization: Default::default(),
|
|
||||||
backend_requests: Default::default(),
|
|
||||||
chain_id: Default::default(),
|
|
||||||
error_response: Default::default(),
|
|
||||||
kafka_debug_logger: Default::default(),
|
|
||||||
method: Default::default(),
|
|
||||||
no_servers: Default::default(),
|
|
||||||
request_bytes: Default::default(),
|
|
||||||
request_ulid: Default::default(),
|
|
||||||
response_bytes: Default::default(),
|
|
||||||
response_from_backup_rpc: Default::default(),
|
|
||||||
response_millis: Default::default(),
|
|
||||||
response_timestamp: Default::default(),
|
|
||||||
start_instant: Instant::now(),
|
|
||||||
stat_sender: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequestMetadata {
|
impl RequestMetadata {
|
||||||
pub fn proxy_mode(&self) -> ProxyMode {
|
pub fn proxy_mode(&self) -> ProxyMode {
|
||||||
self.authorization
|
self.authorization
|
||||||
|
@ -531,6 +512,7 @@ impl RequestMetadata {
|
||||||
response_timestamp: 0.into(),
|
response_timestamp: 0.into(),
|
||||||
start_instant: Instant::now(),
|
start_instant: Instant::now(),
|
||||||
stat_sender: app.stat_sender.clone(),
|
stat_sender: app.stat_sender.clone(),
|
||||||
|
user_error_response: false.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Arc::new(x)
|
Arc::new(x)
|
||||||
|
|
|
@ -852,9 +852,11 @@ impl Web3Rpcs {
|
||||||
request_metadata
|
request_metadata
|
||||||
.response_from_backup_rpc
|
.response_from_backup_rpc
|
||||||
.store(is_backup_response, Ordering::Release);
|
.store(is_backup_response, Ordering::Release);
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(request_metadata) = request_metadata {
|
request_metadata
|
||||||
|
.user_error_response
|
||||||
|
.store(false, Ordering::Release);
|
||||||
|
|
||||||
request_metadata
|
request_metadata
|
||||||
.error_response
|
.error_response
|
||||||
.store(false, Ordering::Release);
|
.store(false, Ordering::Release);
|
||||||
|
@ -863,21 +865,29 @@ impl Web3Rpcs {
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
// trace!(?response, "rpc error");
|
|
||||||
|
|
||||||
// TODO: separate tracking for jsonrpc error and web3 proxy error!
|
|
||||||
if let Some(request_metadata) = request_metadata {
|
|
||||||
request_metadata
|
|
||||||
.error_response
|
|
||||||
.store(true, Ordering::Release);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: if this is an error, do NOT return. continue to try on another server
|
// TODO: if this is an error, do NOT return. continue to try on another server
|
||||||
let error = match JsonRpcErrorData::try_from(&error) {
|
let error = match JsonRpcErrorData::try_from(&error) {
|
||||||
Ok(x) => x,
|
Ok(x) => {
|
||||||
|
if let Some(request_metadata) = request_metadata {
|
||||||
|
request_metadata
|
||||||
|
.user_error_response
|
||||||
|
.store(true, Ordering::Release);
|
||||||
|
}
|
||||||
|
x
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(?err, "error from {}", rpc);
|
warn!(?err, "error from {}", rpc);
|
||||||
|
|
||||||
|
if let Some(request_metadata) = request_metadata {
|
||||||
|
request_metadata
|
||||||
|
.error_response
|
||||||
|
.store(true, Ordering::Release);
|
||||||
|
|
||||||
|
request_metadata
|
||||||
|
.user_error_response
|
||||||
|
.store(false, Ordering::Release);
|
||||||
|
}
|
||||||
|
|
||||||
last_provider_error = Some(error);
|
last_provider_error = Some(error);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -1012,19 +1022,27 @@ impl Web3Rpcs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpenRequestResult::NotReady => {
|
OpenRequestResult::NotReady => {
|
||||||
|
if let Some(request_metadata) = request_metadata {
|
||||||
|
request_metadata
|
||||||
|
.error_response
|
||||||
|
.store(true, Ordering::Release);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: do we need this here, or do we do it somewhere else? like, the code could change and a try operator in here would skip this increment
|
|
||||||
if let Some(request_metadata) = request_metadata {
|
|
||||||
request_metadata
|
|
||||||
.error_response
|
|
||||||
.store(true, Ordering::Release);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(err) = method_not_available_response {
|
if let Some(err) = method_not_available_response {
|
||||||
|
if let Some(request_metadata) = request_metadata {
|
||||||
|
request_metadata
|
||||||
|
.error_response
|
||||||
|
.store(false, Ordering::Release);
|
||||||
|
|
||||||
|
request_metadata
|
||||||
|
.user_error_response
|
||||||
|
.store(true, Ordering::Release);
|
||||||
|
}
|
||||||
|
|
||||||
// this error response is likely the user's fault
|
// this error response is likely the user's fault
|
||||||
// TODO: emit a stat for unsupported methods. then we can know what there is demand for or if we are missing a feature
|
// TODO: emit a stat for unsupported methods. then we can know what there is demand for or if we are missing a feature
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
|
|
|
@ -263,6 +263,7 @@ pub async fn query_user_stats<'a>(
|
||||||
"error_response",
|
"error_response",
|
||||||
"method",
|
"method",
|
||||||
"rpc_secret_key_id",
|
"rpc_secret_key_id",
|
||||||
|
"user_error_response",
|
||||||
]"#
|
]"#
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -332,7 +333,7 @@ pub async fn query_user_stats<'a>(
|
||||||
// TODO: lower log level
|
// TODO: lower log level
|
||||||
debug!("Raw query to db is: {:#}", query);
|
debug!("Raw query to db is: {:#}", query);
|
||||||
let query = Query::new(query.to_string());
|
let query = Query::new(query.to_string());
|
||||||
trace!("Query to db is: {:#?}", query);
|
trace!(?query, "influx");
|
||||||
|
|
||||||
// Make the query and collect all data
|
// Make the query and collect all data
|
||||||
let raw_influx_responses: Vec<FluxRecord> = influxdb_client
|
let raw_influx_responses: Vec<FluxRecord> = influxdb_client
|
||||||
|
@ -575,7 +576,25 @@ pub async fn query_user_stats<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("error_response should always be a Long!");
|
error!("error_response should always be a String!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if stat_response_type == StatType::Detailed && key == "user_error_response" {
|
||||||
|
match value {
|
||||||
|
influxdb2_structmap::value::Value::String(inner) => {
|
||||||
|
out.insert(
|
||||||
|
"user_error_response",
|
||||||
|
if inner == "true" {
|
||||||
|
serde_json::Value::Bool(true)
|
||||||
|
} else if inner == "false" {
|
||||||
|
serde_json::Value::Bool(false)
|
||||||
|
} else {
|
||||||
|
serde_json::Value::String("error".to_owned())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
error!("user_error_response should always be a String!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ use std::borrow::Cow;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::atomic::{self, Ordering};
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
|
@ -61,6 +61,8 @@ pub struct RpcQueryStats {
|
||||||
/// The cost of the query in USD
|
/// The cost of the query in USD
|
||||||
/// If the user is on a free tier, this is still calculated so we know how much we are giving away.
|
/// If the user is on a free tier, this is still calculated so we know how much we are giving away.
|
||||||
pub compute_unit_cost: Decimal,
|
pub compute_unit_cost: Decimal,
|
||||||
|
/// If the request is invalid or received a jsonrpc error response (excluding reverts)
|
||||||
|
pub user_error_response: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, From, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, From, Hash, PartialEq, Eq)]
|
||||||
|
@ -71,11 +73,13 @@ pub struct RpcQueryKey {
|
||||||
response_timestamp: i64,
|
response_timestamp: i64,
|
||||||
/// true if an archive server was needed to serve the request.
|
/// true if an archive server was needed to serve the request.
|
||||||
archive_needed: bool,
|
archive_needed: bool,
|
||||||
/// true if the response was some sort of JSONRPC error.
|
/// true if the response was some sort of application error.
|
||||||
error_response: bool,
|
error_response: bool,
|
||||||
|
/// true if the response was some sort of JSONRPC error.
|
||||||
|
user_error_response: bool,
|
||||||
/// the rpc method used.
|
/// the rpc method used.
|
||||||
method: Cow<'static, str>,
|
method: Cow<'static, str>,
|
||||||
/// origin tracking was opt-in. Now it is "None"
|
/// origin tracking **was** opt-in. Now, it is always "None"
|
||||||
origin: Option<Origin>,
|
origin: Option<Origin>,
|
||||||
/// None if the public url was used.
|
/// None if the public url was used.
|
||||||
rpc_secret_key_id: Option<NonZeroU64>,
|
rpc_secret_key_id: Option<NonZeroU64>,
|
||||||
|
@ -103,6 +107,9 @@ impl RpcQueryStats {
|
||||||
// we used to optionally store origin, but wallets don't set it, so its almost always None
|
// we used to optionally store origin, but wallets don't set it, so its almost always None
|
||||||
let origin = None;
|
let origin = None;
|
||||||
|
|
||||||
|
// user_error_response is always set to false because we don't bother tracking this in the database
|
||||||
|
let user_error_response = false;
|
||||||
|
|
||||||
// Depending on method, add some arithmetic around calculating credits_used
|
// Depending on method, add some arithmetic around calculating credits_used
|
||||||
// I think balance should not go here, this looks more like a key thingy
|
// I think balance should not go here, this looks more like a key thingy
|
||||||
RpcQueryKey {
|
RpcQueryKey {
|
||||||
|
@ -113,6 +120,7 @@ impl RpcQueryStats {
|
||||||
rpc_secret_key_id,
|
rpc_secret_key_id,
|
||||||
rpc_key_user_id: self.authorization.checks.user_id.try_into().ok(),
|
rpc_key_user_id: self.authorization.checks.user_id.try_into().ok(),
|
||||||
origin,
|
origin,
|
||||||
|
user_error_response,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +141,7 @@ impl RpcQueryStats {
|
||||||
method,
|
method,
|
||||||
rpc_secret_key_id,
|
rpc_secret_key_id,
|
||||||
rpc_key_user_id: self.authorization.checks.user_id.try_into().ok(),
|
rpc_key_user_id: self.authorization.checks.user_id.try_into().ok(),
|
||||||
|
user_error_response: self.user_error_response,
|
||||||
origin,
|
origin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,6 +160,7 @@ impl RpcQueryStats {
|
||||||
method,
|
method,
|
||||||
rpc_secret_key_id: self.authorization.checks.rpc_secret_key_id,
|
rpc_secret_key_id: self.authorization.checks.rpc_secret_key_id,
|
||||||
rpc_key_user_id: self.authorization.checks.user_id.try_into().ok(),
|
rpc_key_user_id: self.authorization.checks.user_id.try_into().ok(),
|
||||||
|
user_error_response: self.user_error_response,
|
||||||
origin,
|
origin,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -732,6 +742,7 @@ impl BufferedRpcQueryStats {
|
||||||
builder = builder
|
builder = builder
|
||||||
.tag("archive_needed", key.archive_needed.to_string())
|
.tag("archive_needed", key.archive_needed.to_string())
|
||||||
.tag("error_response", key.error_response.to_string())
|
.tag("error_response", key.error_response.to_string())
|
||||||
|
.tag("user_error_response", key.user_error_response.to_string())
|
||||||
.field("frontend_requests", self.frontend_requests as i64)
|
.field("frontend_requests", self.frontend_requests as i64)
|
||||||
.field("backend_requests", self.backend_requests as i64)
|
.field("backend_requests", self.backend_requests as i64)
|
||||||
.field("no_servers", self.no_servers as i64)
|
.field("no_servers", self.no_servers as i64)
|
||||||
|
@ -784,9 +795,11 @@ impl TryFrom<RequestMetadata> for RpcQueryStats {
|
||||||
let response_bytes = metadata.response_bytes.load(Ordering::Acquire);
|
let response_bytes = metadata.response_bytes.load(Ordering::Acquire);
|
||||||
|
|
||||||
let mut error_response = metadata.error_response.load(Ordering::Acquire);
|
let mut error_response = metadata.error_response.load(Ordering::Acquire);
|
||||||
let mut response_millis = metadata.response_millis.load(atomic::Ordering::Acquire);
|
let mut response_millis = metadata.response_millis.load(Ordering::Acquire);
|
||||||
|
|
||||||
let response_timestamp = match metadata.response_timestamp.load(atomic::Ordering::Acquire) {
|
let user_error_response = metadata.user_error_response.load(Ordering::Acquire);
|
||||||
|
|
||||||
|
let response_timestamp = match metadata.response_timestamp.load(Ordering::Acquire) {
|
||||||
0 => {
|
0 => {
|
||||||
// no response timestamp!
|
// no response timestamp!
|
||||||
if !error_response {
|
if !error_response {
|
||||||
|
@ -820,7 +833,7 @@ impl TryFrom<RequestMetadata> for RpcQueryStats {
|
||||||
|
|
||||||
let cache_hit = !backend_rpcs_used.is_empty();
|
let cache_hit = !backend_rpcs_used.is_empty();
|
||||||
|
|
||||||
let compute_unit_cost = cu.cost(archive_request, cache_hit, usd_per_cu);
|
let compute_unit_cost = cu.cost(archive_request, cache_hit, error_response, usd_per_cu);
|
||||||
|
|
||||||
let method = mem::take(&mut metadata.method);
|
let method = mem::take(&mut metadata.method);
|
||||||
|
|
||||||
|
@ -836,6 +849,7 @@ impl TryFrom<RequestMetadata> for RpcQueryStats {
|
||||||
response_bytes,
|
response_bytes,
|
||||||
response_millis,
|
response_millis,
|
||||||
response_timestamp,
|
response_timestamp,
|
||||||
|
user_error_response,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(x)
|
Ok(x)
|
||||||
|
|
|
@ -64,6 +64,7 @@ impl StatBuffer {
|
||||||
user_balance_cache: Option<UserBalanceCache>,
|
user_balance_cache: Option<UserBalanceCache>,
|
||||||
shutdown_receiver: broadcast::Receiver<()>,
|
shutdown_receiver: broadcast::Receiver<()>,
|
||||||
tsdb_save_interval_seconds: u32,
|
tsdb_save_interval_seconds: u32,
|
||||||
|
flush_receiver: broadcast::Receiver<()>,
|
||||||
) -> anyhow::Result<Option<SpawnedStatBuffer>> {
|
) -> anyhow::Result<Option<SpawnedStatBuffer>> {
|
||||||
if db_conn.is_none() && influxdb_client.is_none() {
|
if db_conn.is_none() && influxdb_client.is_none() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
@ -89,7 +90,7 @@ impl StatBuffer {
|
||||||
|
|
||||||
// any errors inside this task will cause the application to exit
|
// any errors inside this task will cause the application to exit
|
||||||
let handle = tokio::spawn(async move {
|
let handle = tokio::spawn(async move {
|
||||||
new.aggregate_and_save_loop(bucket, stat_receiver, shutdown_receiver)
|
new.aggregate_and_save_loop(bucket, stat_receiver, shutdown_receiver, flush_receiver)
|
||||||
.await
|
.await
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -101,6 +102,7 @@ impl StatBuffer {
|
||||||
bucket: String,
|
bucket: String,
|
||||||
stat_receiver: flume::Receiver<AppStat>,
|
stat_receiver: flume::Receiver<AppStat>,
|
||||||
mut shutdown_receiver: broadcast::Receiver<()>,
|
mut shutdown_receiver: broadcast::Receiver<()>,
|
||||||
|
mut flush_receiver: broadcast::Receiver<()>,
|
||||||
) -> Web3ProxyResult<()> {
|
) -> Web3ProxyResult<()> {
|
||||||
let mut tsdb_save_interval =
|
let mut tsdb_save_interval =
|
||||||
interval(Duration::from_secs(self.tsdb_save_interval_seconds as u64));
|
interval(Duration::from_secs(self.tsdb_save_interval_seconds as u64));
|
||||||
|
@ -150,6 +152,19 @@ impl StatBuffer {
|
||||||
trace!("Saved {} stats to the tsdb", count);
|
trace!("Saved {} stats to the tsdb", count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ = flush_receiver.recv() => {
|
||||||
|
trace!("flush");
|
||||||
|
|
||||||
|
let count = self.save_tsdb_stats(&bucket).await;
|
||||||
|
if count > 0 {
|
||||||
|
trace!("Flushed {} stats to the tsdb", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = self.save_relational_stats().await;
|
||||||
|
if count > 0 {
|
||||||
|
trace!("Flushed {} stats to the relational db", count);
|
||||||
|
}
|
||||||
|
}
|
||||||
x = shutdown_receiver.recv() => {
|
x = shutdown_receiver.recv() => {
|
||||||
match x {
|
match x {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
|
|
@ -72,6 +72,8 @@ impl MigrateStatsToV2SubCommand {
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (_flush_sender, flush_receiver) = broadcast::channel(1);
|
||||||
|
|
||||||
// Spawn the stat-sender
|
// Spawn the stat-sender
|
||||||
let emitter_spawn = StatBuffer::try_spawn(
|
let emitter_spawn = StatBuffer::try_spawn(
|
||||||
BILLING_PERIOD_SECONDS,
|
BILLING_PERIOD_SECONDS,
|
||||||
|
@ -88,6 +90,7 @@ impl MigrateStatsToV2SubCommand {
|
||||||
None,
|
None,
|
||||||
rpc_account_shutdown_recevier,
|
rpc_account_shutdown_recevier,
|
||||||
1,
|
1,
|
||||||
|
flush_receiver,
|
||||||
)
|
)
|
||||||
.context("Error spawning stat buffer")?
|
.context("Error spawning stat buffer")?
|
||||||
.context("No stat buffer spawned. Maybe missing influx or db credentials?")?;
|
.context("No stat buffer spawned. Maybe missing influx or db credentials?")?;
|
||||||
|
@ -203,6 +206,7 @@ impl MigrateStatsToV2SubCommand {
|
||||||
start_instant: Instant::now(),
|
start_instant: Instant::now(),
|
||||||
stat_sender: Some(stat_sender.clone()),
|
stat_sender: Some(stat_sender.clone()),
|
||||||
request_ulid,
|
request_ulid,
|
||||||
|
user_error_response: false.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(x) = request_metadata.try_send_stat()? {
|
if let Some(x) = request_metadata.try_send_stat()? {
|
||||||
|
|
|
@ -42,6 +42,7 @@ impl ProxydSubCommand {
|
||||||
|
|
||||||
let frontend_port = Arc::new(self.port.into());
|
let frontend_port = Arc::new(self.port.into());
|
||||||
let prometheus_port = Arc::new(self.prometheus_port.into());
|
let prometheus_port = Arc::new(self.prometheus_port.into());
|
||||||
|
let (flush_stat_buffer_sender, _) = broadcast::channel(1);
|
||||||
|
|
||||||
Self::_main(
|
Self::_main(
|
||||||
top_config,
|
top_config,
|
||||||
|
@ -50,6 +51,7 @@ impl ProxydSubCommand {
|
||||||
prometheus_port,
|
prometheus_port,
|
||||||
num_workers,
|
num_workers,
|
||||||
shutdown_sender,
|
shutdown_sender,
|
||||||
|
flush_stat_buffer_sender,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -62,14 +64,11 @@ impl ProxydSubCommand {
|
||||||
prometheus_port: Arc<AtomicU16>,
|
prometheus_port: Arc<AtomicU16>,
|
||||||
num_workers: usize,
|
num_workers: usize,
|
||||||
frontend_shutdown_sender: broadcast::Sender<()>,
|
frontend_shutdown_sender: broadcast::Sender<()>,
|
||||||
|
flush_stat_buffer_sender: broadcast::Sender<()>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// tokio has code for catching ctrl+c so we use that
|
// tokio has code for catching ctrl+c so we use that to shut down in most cases
|
||||||
// this shutdown sender is currently only used in tests, but we might make a /shutdown endpoint or something
|
// frontend_shutdown_sender is currently only used in tests, but we might make a /shutdown endpoint or something
|
||||||
// we do not need this receiver. new receivers are made by `shutdown_sender.subscribe()`
|
// we do not need this receiver. new receivers are made by `shutdown_sender.subscribe()`
|
||||||
|
|
||||||
// TODO: should we use a watch or broadcast for these?
|
|
||||||
// Maybe this one ?
|
|
||||||
// let mut shutdown_receiver = shutdown_sender.subscribe();
|
|
||||||
let (app_shutdown_sender, _app_shutdown_receiver) = broadcast::channel(1);
|
let (app_shutdown_sender, _app_shutdown_receiver) = broadcast::channel(1);
|
||||||
|
|
||||||
let frontend_shutdown_receiver = frontend_shutdown_sender.subscribe();
|
let frontend_shutdown_receiver = frontend_shutdown_sender.subscribe();
|
||||||
|
@ -86,6 +85,7 @@ impl ProxydSubCommand {
|
||||||
top_config.clone(),
|
top_config.clone(),
|
||||||
num_workers,
|
num_workers,
|
||||||
app_shutdown_sender.clone(),
|
app_shutdown_sender.clone(),
|
||||||
|
flush_stat_buffer_sender.subscribe(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,9 @@ pub struct TestApp {
|
||||||
/// connection to the proxy that is connected to anil.
|
/// connection to the proxy that is connected to anil.
|
||||||
pub proxy_provider: Provider<Http>,
|
pub proxy_provider: Provider<Http>,
|
||||||
|
|
||||||
|
/// tell the app to flush stats to the database
|
||||||
|
flush_stat_buffer_sender: broadcast::Sender<()>,
|
||||||
|
|
||||||
/// tell the app to shut down (use `self.stop()`).
|
/// tell the app to shut down (use `self.stop()`).
|
||||||
shutdown_sender: broadcast::Sender<()>,
|
shutdown_sender: broadcast::Sender<()>,
|
||||||
}
|
}
|
||||||
|
@ -269,6 +272,8 @@ impl TestApp {
|
||||||
let frontend_port_arc = Arc::new(AtomicU16::new(0));
|
let frontend_port_arc = Arc::new(AtomicU16::new(0));
|
||||||
let prometheus_port_arc = Arc::new(AtomicU16::new(0));
|
let prometheus_port_arc = Arc::new(AtomicU16::new(0));
|
||||||
|
|
||||||
|
let (flush_stat_buffer_sender, _flush_stat_buffer_receiver) = broadcast::channel(1);
|
||||||
|
|
||||||
// spawn the app
|
// spawn the app
|
||||||
// TODO: spawn in a thread so we can run from non-async tests and so the Drop impl can wait for it to stop
|
// TODO: spawn in a thread so we can run from non-async tests and so the Drop impl can wait for it to stop
|
||||||
let handle = {
|
let handle = {
|
||||||
|
@ -279,6 +284,7 @@ impl TestApp {
|
||||||
prometheus_port_arc,
|
prometheus_port_arc,
|
||||||
num_workers,
|
num_workers,
|
||||||
shutdown_sender.clone(),
|
shutdown_sender.clone(),
|
||||||
|
flush_stat_buffer_sender.clone(),
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -304,6 +310,7 @@ impl TestApp {
|
||||||
db,
|
db,
|
||||||
proxy_handle: Mutex::new(Some(handle)),
|
proxy_handle: Mutex::new(Some(handle)),
|
||||||
proxy_provider,
|
proxy_provider,
|
||||||
|
flush_stat_buffer_sender,
|
||||||
shutdown_sender,
|
shutdown_sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,6 +320,10 @@ impl TestApp {
|
||||||
self.db.as_ref().unwrap().conn.as_ref().unwrap()
|
self.db.as_ref().unwrap().conn.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flush_stats(&self) {
|
||||||
|
self.flush_stat_buffer_sender.send(()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stop(&self) -> Result<usize, SendError<()>> {
|
pub fn stop(&self) -> Result<usize, SendError<()>> {
|
||||||
self.shutdown_sender.send(())
|
self.shutdown_sender.send(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue