diff --git a/.changeset/early-points-provide.md b/.changeset/early-points-provide.md new file mode 100644 index 000000000..8668fd626 --- /dev/null +++ b/.changeset/early-points-provide.md @@ -0,0 +1,8 @@ +--- +'@lagon/cli': patch +'@lagon/runtime': patch +'@lagon/serverless': patch +'@lagon/wpt-runner': patch +--- + +Replace once_cell with std's OnceLock diff --git a/.changeset/neat-taxis-run.md b/.changeset/neat-taxis-run.md new file mode 100644 index 000000000..c087e6e82 --- /dev/null +++ b/.changeset/neat-taxis-run.md @@ -0,0 +1,5 @@ +--- +'@lagon/serverless': patch +--- + +Set region label for prometheus exporter globally diff --git a/Cargo.lock b/Cargo.lock index 38269f07d..b044936d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1791,7 +1791,6 @@ dependencies = [ "lagon-runtime-isolate", "lagon-runtime-utils", "notify", - "once_cell", "pathdiff", "serde", "serde_json", @@ -1828,7 +1827,6 @@ dependencies = [ "hmac", "lagon-runtime-v8-utils", "num-traits", - "once_cell", "p256", "p384", "rand", @@ -1865,7 +1863,6 @@ dependencies = [ "lagon-runtime-v8-utils", "linked-hash-map", "log", - "once_cell", "tokio", "v8", ] @@ -1913,7 +1910,6 @@ dependencies = [ "metrics", "metrics-exporter-prometheus", "mysql", - "once_cell", "reqwest", "serde", "serde_json", @@ -1968,7 +1964,6 @@ dependencies = [ "lagon-runtime", "lagon-runtime-http", "lagon-runtime-isolate", - "once_cell", "tokio", ] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 5239e4191..b47240fb4 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -26,4 +26,3 @@ notify = "6.0.0" envfile = "0.2.1" anyhow = "1.0.71" urlencoding = "2.1.2" -once_cell = "1.17.1" diff --git a/crates/cli/src/commands/deploy.rs b/crates/cli/src/commands/deploy.rs index 99ed47968..ac5279386 100644 --- a/crates/cli/src/commands/deploy.rs +++ b/crates/cli/src/commands/deploy.rs @@ -1,4 +1,6 @@ -use crate::utils::{create_deployment, print_progress, resolve_path, Config, TrpcClient, THEME}; +use crate::utils::{ + create_deployment, get_theme, print_progress, resolve_path, Config, TrpcClient, +}; use anyhow::{anyhow, Result}; use dialoguer::{console::style, Confirm, Input, Select}; use serde::{Deserialize, Serialize}; @@ -77,14 +79,14 @@ pub async fn deploy( .await?; let organizations = response.result.data; - let index = Select::with_theme(&*THEME) + let index = Select::with_theme(get_theme()) .items(&organizations) .default(0) .with_prompt("Which Organization would you like to deploy to?") .interact()?; let organization = &organizations[index]; - match Confirm::with_theme(&*THEME) + match Confirm::with_theme(get_theme()) .with_prompt("Link to an existing Function?") .default(false) .interact()? @@ -95,7 +97,7 @@ pub async fn deploy( .await?; let functions = response.result.data; - let index = Select::with_theme(&*THEME) + let index = Select::with_theme(get_theme()) .items(&functions) .default(0) .with_prompt("Which Function would you like to link?") @@ -110,7 +112,7 @@ pub async fn deploy( create_deployment(config, &function_config, is_production, &root, true).await?; } false => { - let name = Input::::with_theme(&*THEME) + let name = Input::::with_theme(get_theme()) .with_prompt("What's the name of this new Function?") .interact_text()?; diff --git a/crates/cli/src/commands/link.rs b/crates/cli/src/commands/link.rs index 7d1967b58..53e64d610 100644 --- a/crates/cli/src/commands/link.rs +++ b/crates/cli/src/commands/link.rs @@ -1,6 +1,6 @@ use crate::{ commands::deploy::{FunctionsResponse, OrganizationsResponse}, - utils::{get_root, Config, FunctionConfig, TrpcClient, THEME}, + utils::{get_root, get_theme, Config, FunctionConfig, TrpcClient}, }; use anyhow::{anyhow, Result}; use dialoguer::{console::style, Select}; @@ -27,7 +27,7 @@ pub async fn link(directory: Option) -> Result<()> { .await?; let organizations = response.result.data; - let index = Select::with_theme(&*THEME) + let index = Select::with_theme(get_theme()) .items(&organizations) .default(0) .with_prompt("Which Organization would you like to link from?") @@ -39,7 +39,7 @@ pub async fn link(directory: Option) -> Result<()> { .await?; let functions = response.result.data; - let index = Select::with_theme(&*THEME) + let index = Select::with_theme(get_theme()) .items(&functions) .default(0) .with_prompt("Which Function would you like to link?") diff --git a/crates/cli/src/commands/login.rs b/crates/cli/src/commands/login.rs index 9c19f27be..c6eec32b6 100644 --- a/crates/cli/src/commands/login.rs +++ b/crates/cli/src/commands/login.rs @@ -1,4 +1,4 @@ -use crate::utils::{print_progress, Config, TrpcClient, THEME}; +use crate::utils::{get_theme, print_progress, Config, TrpcClient}; use anyhow::{anyhow, Result}; use dialoguer::{console::style, Confirm, Password}; use serde::{Deserialize, Serialize}; @@ -17,7 +17,7 @@ pub async fn login() -> Result<()> { let mut config = Config::new()?; if config.token.is_some() - && !Confirm::with_theme(&*THEME) + && !Confirm::with_theme(get_theme()) .with_prompt("You are already logged in. Do you want to log out and log in again?") .default(true) .interact()? @@ -45,7 +45,7 @@ pub async fn login() -> Result<()> { ); println!(); - let code = Password::with_theme(&*THEME) + let code = Password::with_theme(get_theme()) .with_prompt("Paste the verification code from your browser here") .interact()?; diff --git a/crates/cli/src/commands/logout.rs b/crates/cli/src/commands/logout.rs index 6b216ad35..401a04167 100644 --- a/crates/cli/src/commands/logout.rs +++ b/crates/cli/src/commands/logout.rs @@ -1,4 +1,4 @@ -use crate::utils::{Config, THEME}; +use crate::utils::{get_theme, Config}; use anyhow::{anyhow, Result}; use dialoguer::{console::style, Confirm}; @@ -9,7 +9,7 @@ pub fn logout() -> Result<()> { return Err(anyhow!("You are not logged in.")); } - match Confirm::with_theme(&*THEME) + match Confirm::with_theme(get_theme()) .with_prompt("Do you really want to log out?") .default(true) .interact()? diff --git a/crates/cli/src/commands/promote.rs b/crates/cli/src/commands/promote.rs index 33bbe6657..4604e070e 100644 --- a/crates/cli/src/commands/promote.rs +++ b/crates/cli/src/commands/promote.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_root, print_progress, Config, FunctionConfig, TrpcClient, THEME}; +use crate::utils::{get_root, get_theme, print_progress, Config, FunctionConfig, TrpcClient}; use anyhow::{anyhow, Result}; use dialoguer::{console::style, Confirm}; use serde::{Deserialize, Serialize}; @@ -29,7 +29,7 @@ pub async fn promote(deployment_id: String, directory: Option) -> Resul let root = get_root(directory); let function_config = FunctionConfig::load(&root, None, None)?; - match Confirm::with_theme(&*THEME) + match Confirm::with_theme(get_theme()) .with_prompt("Do you really want to promote this Deployment to production?") .default(true) .interact()? diff --git a/crates/cli/src/commands/rm.rs b/crates/cli/src/commands/rm.rs index 00f11b4af..17402d70e 100644 --- a/crates/cli/src/commands/rm.rs +++ b/crates/cli/src/commands/rm.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_root, print_progress, Config, FunctionConfig, TrpcClient, THEME}; +use crate::utils::{get_root, get_theme, print_progress, Config, FunctionConfig, TrpcClient}; use anyhow::{anyhow, Result}; use dialoguer::{console::style, Confirm}; use serde::{Deserialize, Serialize}; @@ -28,7 +28,7 @@ pub async fn rm(directory: Option) -> Result<()> { let root = get_root(directory); let function_config = FunctionConfig::load(&root, None, None)?; - match Confirm::with_theme(&*THEME) + match Confirm::with_theme(get_theme()) .with_prompt( "Do you really want to completely delete this Function, its Deployments, statistics and logs?", ) diff --git a/crates/cli/src/commands/undeploy.rs b/crates/cli/src/commands/undeploy.rs index 18af0fdf9..0d813d293 100644 --- a/crates/cli/src/commands/undeploy.rs +++ b/crates/cli/src/commands/undeploy.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_root, print_progress, Config, FunctionConfig, TrpcClient, THEME}; +use crate::utils::{get_root, get_theme, print_progress, Config, FunctionConfig, TrpcClient}; use anyhow::{anyhow, Result}; use dialoguer::{console::style, Confirm}; use serde::{Deserialize, Serialize}; @@ -29,7 +29,7 @@ pub async fn undeploy(deployment_id: String, directory: Option) -> Resu let root = get_root(directory); let function_config = FunctionConfig::load(&root, None, None)?; - match Confirm::with_theme(&*THEME) + match Confirm::with_theme(get_theme()) .with_prompt("Do you really want to delete this Deployment?") .default(false) .interact()? diff --git a/crates/cli/src/utils/console.rs b/crates/cli/src/utils/console.rs index 9790b5757..2c7cd5c32 100644 --- a/crates/cli/src/utils/console.rs +++ b/crates/cli/src/utils/console.rs @@ -1,10 +1,9 @@ use dialoguer::{ console::{style, Style}, - theme::ColorfulTheme, + theme::{ColorfulTheme, Theme}, }; use indicatif::{ProgressBar, ProgressStyle}; -use once_cell::sync::Lazy; -use std::time::Duration; +use std::{sync::OnceLock, time::Duration}; pub fn print_progress(message: &str) -> impl Fn() + '_ { let index_progress = ProgressBar::new_spinner(); @@ -36,24 +35,28 @@ pub fn print_progress(message: &str) -> impl Fn() + '_ { } } -pub static THEME: Lazy = Lazy::new(|| ColorfulTheme { - defaults_style: Style::new().for_stderr().blue(), - prompt_style: Style::new().for_stderr().bold(), - prompt_prefix: style(" ○".to_string()).for_stderr().magenta(), - prompt_suffix: style("›".to_string()).for_stderr().black().bright(), - success_prefix: style(" ●".to_string()).for_stderr().magenta(), - success_suffix: style("›".to_string()).for_stderr().black().bright(), - error_prefix: style("✕".to_string()).for_stderr().red(), - error_style: Style::new().for_stderr(), - hint_style: Style::new().for_stderr().black().bright(), - values_style: Style::new().for_stderr().blue(), - active_item_style: Style::new().for_stderr().blue(), - inactive_item_style: Style::new().for_stderr(), - active_item_prefix: style("›".to_string()).for_stderr().blue(), - inactive_item_prefix: style(" ".to_string()).for_stderr(), - checked_item_prefix: style("✔".to_string()).for_stderr().green(), - unchecked_item_prefix: style("✔".to_string()).for_stderr().black(), - picked_item_prefix: style("❯".to_string()).for_stderr().green(), - unpicked_item_prefix: style(" ".to_string()).for_stderr(), - inline_selections: true, -}); +static THEME: OnceLock = OnceLock::new(); + +pub fn get_theme() -> &'static dyn Theme { + THEME.get_or_init(|| ColorfulTheme { + defaults_style: Style::new().for_stderr().blue(), + prompt_style: Style::new().for_stderr().bold(), + prompt_prefix: style(" ○".to_string()).for_stderr().magenta(), + prompt_suffix: style("›".to_string()).for_stderr().black().bright(), + success_prefix: style(" ●".to_string()).for_stderr().magenta(), + success_suffix: style("›".to_string()).for_stderr().black().bright(), + error_prefix: style("✕".to_string()).for_stderr().red(), + error_style: Style::new().for_stderr(), + hint_style: Style::new().for_stderr().black().bright(), + values_style: Style::new().for_stderr().blue(), + active_item_style: Style::new().for_stderr().blue(), + inactive_item_style: Style::new().for_stderr(), + active_item_prefix: style("›".to_string()).for_stderr().blue(), + inactive_item_prefix: style(" ".to_string()).for_stderr(), + checked_item_prefix: style("✔".to_string()).for_stderr().green(), + unchecked_item_prefix: style("✔".to_string()).for_stderr().black(), + picked_item_prefix: style("❯".to_string()).for_stderr().green(), + unpicked_item_prefix: style(" ".to_string()).for_stderr(), + inline_selections: true, + }) +} diff --git a/crates/cli/src/utils/deployments.rs b/crates/cli/src/utils/deployments.rs index 311ead3c8..57d657f83 100644 --- a/crates/cli/src/utils/deployments.rs +++ b/crates/cli/src/utils/deployments.rs @@ -1,7 +1,7 @@ use super::{ validate_assets_dir, validate_code_file, Config, MAX_ASSET_SIZE_MB, MAX_FUNCTION_SIZE_MB, }; -use crate::utils::{print_progress, TrpcClient, THEME}; +use crate::utils::{get_theme, print_progress, TrpcClient}; use anyhow::{anyhow, Result}; use dialoguer::console::style; use dialoguer::{Confirm, Input}; @@ -58,7 +58,7 @@ impl FunctionConfig { index } None => { - let index = Input::::with_theme(&*THEME) + let index = Input::::with_theme(get_theme()) .with_prompt(format!( "Path to your Function's entrypoint? {}", style(format!("(relative to {:?})", root.canonicalize()?)) @@ -83,13 +83,13 @@ impl FunctionConfig { ); Some(assets) } - None => match Confirm::with_theme(&*THEME) + None => match Confirm::with_theme(get_theme()) .with_prompt("Do you have a public directory to serve assets from?") .default(false) .interact()? { true => { - let assets = Input::::with_theme(&*THEME) + let assets = Input::::with_theme(get_theme()) .with_prompt(format!( "Path to your Function's public directory? {}", style(format!("(relative to {:?})", root.canonicalize()?)) diff --git a/crates/runtime_crypto/Cargo.toml b/crates/runtime_crypto/Cargo.toml index 9bdb7aee0..23770dff9 100644 --- a/crates/runtime_crypto/Cargo.toml +++ b/crates/runtime_crypto/Cargo.toml @@ -17,7 +17,6 @@ aes = "0.8.2" aes-gcm = "0.10.2" cbc = { version = "0.1.2", features = ["std"] } ring = { version = "0.16.20", features = ["std"] } -once_cell = "1.17.1" num-traits = "0.2.15" rsa = { version = "=0.9.2", default-features = false, features = ["std", "sha2"] } p256 = { version = "0.13.2", features = ["ecdh"] } diff --git a/crates/runtime_crypto/src/methods/generate_key.rs b/crates/runtime_crypto/src/methods/generate_key.rs index 5bf86bc56..4464b22fc 100644 --- a/crates/runtime_crypto/src/methods/generate_key.rs +++ b/crates/runtime_crypto/src/methods/generate_key.rs @@ -1,16 +1,16 @@ use anyhow::{anyhow, Ok, Result}; use num_traits::FromPrimitive; -use once_cell::sync::Lazy; use ring::rand::{SecureRandom, SystemRandom}; use ring::signature::EcdsaKeyPair; use rsa::pkcs1::EncodeRsaPrivateKey; use rsa::rand_core::OsRng; use rsa::{BigUint, RsaPrivateKey}; +use std::sync::OnceLock; use crate::{CryptoNamedCurve, KeyGenAlgorithm, Sha}; -static PUB_EXPONENT_1: Lazy = Lazy::new(|| BigUint::from_u64(3).unwrap()); -static PUB_EXPONENT_2: Lazy = Lazy::new(|| BigUint::from_u64(65537).unwrap()); +static PUB_EXPONENT_1: OnceLock = OnceLock::new(); +static PUB_EXPONENT_2: OnceLock = OnceLock::new(); pub fn generate_key(algorithm: KeyGenAlgorithm) -> Result> { match algorithm { @@ -20,7 +20,9 @@ pub fn generate_key(algorithm: KeyGenAlgorithm) -> Result> { } => { let exponent = BigUint::from_bytes_be(public_exponent); - if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 { + if exponent != *PUB_EXPONENT_1.get_or_init(|| BigUint::from_u64(3).unwrap()) + && exponent != *PUB_EXPONENT_2.get_or_init(|| BigUint::from_u64(65537).unwrap()) + { return Err(anyhow!("Bad public exponent")); } diff --git a/crates/runtime_isolate/Cargo.toml b/crates/runtime_isolate/Cargo.toml index 9089852b5..45e8738b3 100644 --- a/crates/runtime_isolate/Cargo.toml +++ b/crates/runtime_isolate/Cargo.toml @@ -12,7 +12,6 @@ hyper-tls = { version = "0.5.0", features = ["vendored"] } flume = "0.10.14" anyhow = "1.0.71" log = { version = "0.4.18", features = ["std", "kv_unstable"] } -once_cell = "1.17.1" async-recursion = "1.0.4" linked-hash-map = "0.5.6" lagon-runtime-v8-utils = { path = "../runtime_v8_utils" } diff --git a/crates/runtime_isolate/src/bindings/fetch.rs b/crates/runtime_isolate/src/bindings/fetch.rs index ef56acf95..a2fc70378 100644 --- a/crates/runtime_isolate/src/bindings/fetch.rs +++ b/crates/runtime_isolate/src/bindings/fetch.rs @@ -3,14 +3,13 @@ use async_recursion::async_recursion; use hyper::{client::HttpConnector, header::LOCATION, http::Uri, Body, Client, Request, Response}; use hyper_tls::HttpsConnector; use lagon_runtime_http::request_from_v8; -use once_cell::sync::Lazy; +use std::sync::OnceLock; use crate::{bindings::PromiseResult, Isolate}; use super::BindingResult; -static CLIENT: Lazy>> = - Lazy::new(|| Client::builder().build::<_, Body>(HttpsConnector::new())); +static CLIENT: OnceLock>> = OnceLock::new(); type Arg = Request; @@ -84,7 +83,8 @@ async fn make_request( let uri = request.uri().clone(); let (request_a, request_b) = clone_response(request).await?; - let response = CLIENT.request(request_a).await?; + let client = CLIENT.get_or_init(|| Client::builder().build::<_, Body>(HttpsConnector::new())); + let response = client.request(request_a).await?; if response.status().is_redirection() { let mut redirect_url = match response.headers().get(LOCATION) { diff --git a/crates/serverless/Cargo.toml b/crates/serverless/Cargo.toml index 21f457750..86d05b052 100644 --- a/crates/serverless/Cargo.toml +++ b/crates/serverless/Cargo.toml @@ -21,7 +21,6 @@ serde_json = "1.0" metrics = "0.21.0" metrics-exporter-prometheus = { version = "0.12.1", default-features = false, features = ["http-listener"] } log = { version = "0.4.18", features = ["std", "kv_unstable", "kv_unstable_serde"] } -once_cell = "1.17.1" anyhow = "1.0.71" tokio-cron-scheduler = "0.9.4" dashmap = "5.4.0" diff --git a/crates/serverless/src/cronjob.rs b/crates/serverless/src/cronjob.rs index e2ba65388..0d25ce5ce 100644 --- a/crates/serverless/src/cronjob.rs +++ b/crates/serverless/src/cronjob.rs @@ -22,7 +22,7 @@ use uuid::Uuid; use crate::{ clickhouse::{LogRow, RequestRow}, - REGION, SNAPSHOT_BLOB, + get_region, SNAPSHOT_BLOB, }; pub struct Cronjob { @@ -66,7 +66,6 @@ impl Cronjob { let labels = [ ("deployment", deployment.id.clone()), ("function", deployment.function_id.clone()), - ("region", REGION.clone()), ]; let deployment = Arc::clone(&deployment); @@ -107,7 +106,6 @@ impl Cronjob { let labels = [ ("deployment", metadata.0.clone()), ("function", metadata.1.clone()), - ("region", REGION.clone()), ]; decrement_gauge!("lagon_isolates", 1.0, &labels); @@ -119,7 +117,6 @@ impl Cronjob { let labels = [ ("deployment", metadata.0.clone()), ("function", metadata.1.clone()), - ("region", REGION.clone()), ]; histogram!( @@ -181,7 +178,7 @@ impl Cronjob { .write(&RequestRow { function_id: deployment.function_id.clone(), deployment_id: deployment.id.clone(), - region: REGION.clone(), + region: get_region().clone(), bytes_in: 0, bytes_out: 0, cpu_time_micros: elapsed.map(|duration| duration.as_micros()), diff --git a/crates/serverless/src/deployments/mod.rs b/crates/serverless/src/deployments/mod.rs index 36c590c19..231f6063f 100644 --- a/crates/serverless/src/deployments/mod.rs +++ b/crates/serverless/src/deployments/mod.rs @@ -1,4 +1,4 @@ -use crate::REGION; +use crate::get_region; use anyhow::{anyhow, Result}; use dashmap::DashMap; use futures::{stream::FuturesUnordered, StreamExt}; @@ -114,7 +114,7 @@ WHERE OR Function.cronRegion = '{}' ", - REGION.as_str() + get_region() ), |( id, diff --git a/crates/serverless/src/deployments/pubsub.rs b/crates/serverless/src/deployments/pubsub.rs index ea7e9d659..272fa4e6a 100644 --- a/crates/serverless/src/deployments/pubsub.rs +++ b/crates/serverless/src/deployments/pubsub.rs @@ -1,5 +1,5 @@ use super::{download_deployment, filesystem::rm_deployment, Deployment, Deployments}; -use crate::{cronjob::Cronjob, serverless::Workers, REGION}; +use crate::{cronjob::Cronjob, get_region, serverless::Workers}; use anyhow::Result; use futures::StreamExt; use lagon_runtime_isolate::IsolateEvent; @@ -44,10 +44,7 @@ where // Ignore deployments that have a cron set but where // the region isn't this node' region, except for undeploys // because we might remove the cron from the old region - if cron.is_some() - && cron_region != REGION.to_string() - && kind != PubSubMessageKind::Undeploy - { + if cron.is_some() && &cron_region != get_region() && kind != PubSubMessageKind::Undeploy { continue; } @@ -93,7 +90,6 @@ where "status" => "success", "deployment" => deployment.id.clone(), "function" => deployment.function_id.clone(), - "region" => REGION.clone(), ); let domains = deployment.get_domains(); @@ -118,7 +114,6 @@ where "status" => "error", "deployment" => deployment.id.clone(), "function" => deployment.function_id.clone(), - "region" => REGION.clone(), ); error!( deployment = deployment.id; @@ -135,7 +130,6 @@ where "status" => "success", "deployment" => deployment.id.clone(), "function" => deployment.function_id.clone(), - "region" => REGION.clone(), ); let domains = deployment.get_domains(); @@ -165,7 +159,6 @@ where "status" => "error", "deployment" => deployment.id.clone(), "function" => deployment.function_id.clone(), - "region" => REGION.clone(), ); error!(deployment = deployment.id; "Failed to delete deployment: {}", error); } @@ -176,7 +169,6 @@ where "lagon_promotion", "deployment" => deployment.id.clone(), "function" => deployment.function_id.clone(), - "region" => REGION.clone(), ); let previous_id = value["previousDeploymentId"].as_str().unwrap(); diff --git a/crates/serverless/src/lib.rs b/crates/serverless/src/lib.rs index f75b336dd..1e41d33e0 100644 --- a/crates/serverless/src/lib.rs +++ b/crates/serverless/src/lib.rs @@ -1,12 +1,14 @@ -use once_cell::sync::Lazy; -use std::env; +use std::{env, sync::OnceLock}; pub mod clickhouse; pub mod cronjob; pub mod deployments; pub mod serverless; -pub static REGION: Lazy = - Lazy::new(|| env::var("LAGON_REGION").expect("LAGON_REGION must be set")); +static REGION: OnceLock = OnceLock::new(); + +pub fn get_region() -> &'static String { + REGION.get_or_init(|| env::var("LAGON_REGION").expect("LAGON_REGION must be set")) +} pub const SNAPSHOT_BLOB: &[u8] = include_bytes!("../snapshot.bin"); diff --git a/crates/serverless/src/main.rs b/crates/serverless/src/main.rs index ec8e92e17..d5a1a3ecf 100644 --- a/crates/serverless/src/main.rs +++ b/crates/serverless/src/main.rs @@ -2,8 +2,8 @@ use anyhow::Result; use lagon_runtime::{options::RuntimeOptions, Runtime}; use lagon_serverless::clickhouse::{create_client, run_migrations}; use lagon_serverless::deployments::get_deployments; +use lagon_serverless::get_region; use lagon_serverless::serverless::start; -use lagon_serverless::REGION; use lagon_serverless_downloader::{get_bucket, S3BucketDownloader}; use lagon_serverless_logger::init_logger; use lagon_serverless_pubsub::RedisPubSub; @@ -26,7 +26,7 @@ async fn main() -> Result<()> { #[cfg(debug_assertions)] dotenv::dotenv().expect("Failed to load .env file"); - let _flush_guard = init_logger(REGION.clone()).expect("Failed to init logger"); + let _flush_guard = init_logger(get_region().clone()).expect("Failed to init logger"); let runtime = Runtime::new(RuntimeOptions::default()); let addr: SocketAddr = env::var("LAGON_LISTEN_ADDR") @@ -36,7 +36,9 @@ async fn main() -> Result<()> { .expect("PROMETHEUS_LISTEN_ADDR must be set") .parse()?; - let mut builder = PrometheusBuilder::new().with_http_listener(prometheus_addr); + let mut builder = PrometheusBuilder::new() + .with_http_listener(prometheus_addr) + .add_global_label("region", get_region()); if let Ok(allowed_subnet) = env::var("PROMETHEUS_ALLOWED_SUBNET") { if !allowed_subnet.is_empty() { diff --git a/crates/serverless/src/serverless.rs b/crates/serverless/src/serverless.rs index 9519851c9..16d8161c7 100644 --- a/crates/serverless/src/serverless.rs +++ b/crates/serverless/src/serverless.rs @@ -2,7 +2,7 @@ use crate::{ clickhouse::{LogRow, RequestRow}, cronjob::Cronjob, deployments::{cache::run_cache_clear_task, pubsub::listen_pub_sub, Deployments}, - REGION, SNAPSHOT_BLOB, + get_region, SNAPSHOT_BLOB, }; use anyhow::Result; use clickhouse::{inserter::Inserter, Client}; @@ -48,12 +48,11 @@ async fn handle_error( function_id: String, deployment_id: String, request_id: &String, - labels: &[(&'static str, String); 3], inserters: Arc, Inserter)>>, ) { let (level, message) = match result { RunResult::Timeout => { - increment_counter!("lagon_isolate_timeouts", labels); + increment_counter!("lagon_isolate_timeouts", "deployment" => deployment_id.clone(), "function" => function_id.clone()); let message = "Function execution timed out"; warn!(deployment = deployment_id, function = function_id, request = request_id; "{}", message); @@ -61,7 +60,7 @@ async fn handle_error( ("warn", message.into()) } RunResult::MemoryLimit => { - increment_counter!("lagon_isolate_memory_limits", labels); + increment_counter!("lagon_isolate_memory_limits", "deployment" => deployment_id.clone(), "function" => function_id.clone()); let message = "Function execution memory limit reached"; warn!(deployment = deployment_id, function = function_id, request = request_id; "{}", message); @@ -69,7 +68,7 @@ async fn handle_error( ("warn", message.into()) } RunResult::Error(error) => { - increment_counter!("lagon_isolate_errors", labels); + increment_counter!("lagon_isolate_errors", "deployment" => deployment_id.clone(), "function" => function_id.clone()); let message = format!("Function execution error: {}", error); error!(deployment = deployment_id, function = function_id, request = request_id; "{}", message); @@ -88,7 +87,7 @@ async fn handle_error( deployment_id, level: level.to_string(), message, - region: REGION.clone(), + region: get_region().clone(), timestamp: UNIX_EPOCH.elapsed().unwrap().as_secs() as u32, }) .await @@ -117,7 +116,6 @@ async fn handle_request( increment_counter!( "lagon_ignored_requests", "reason" => "No hostname", - "region" => REGION.clone(), ); warn!(req = as_debug!(req), ip = ip, request = request_id; "No Host header found in request"); @@ -132,7 +130,6 @@ async fn handle_request( "lagon_ignored_requests", "reason" => "No deployment", "hostname" => hostname.clone(), - "region" => REGION.clone(), ); warn!(req = as_debug!(req), ip = ip, hostname = hostname, request = request_id; "No deployment found for hostname"); @@ -145,7 +142,6 @@ async fn handle_request( "lagon_ignored_requests", "reason" => "Cron", "hostname" => hostname.clone(), - "region" => REGION.clone(), ); warn!(req = as_debug!(req), ip = ip, hostname = hostname, request = request_id; "Cron deployment cannot be called directly"); @@ -158,12 +154,6 @@ async fn handle_request( let (sender, receiver) = flume::unbounded(); let mut bytes_in = 0; - let labels = [ - ("deployment", deployment.id.clone()), - ("function", deployment.function_id.clone()), - ("region", REGION.clone()), - ]; - let url = req.uri().path(); let is_favicon = url == FAVICON_URL; @@ -204,7 +194,7 @@ async fn handle_request( bytes_in = body.len() as u32; parts.headers.insert(X_FORWARDED_FOR, ip.parse()?); - parts.headers.insert(X_LAGON_REGION, REGION.parse()?); + parts.headers.insert(X_LAGON_REGION, get_region().parse()?); let request = (parts, body); @@ -212,11 +202,10 @@ async fn handle_request( let isolate_sender = workers.entry(deployment_id.clone()).or_insert_with(|| { let handle = Handle::current(); let (sender, receiver) = flume::unbounded(); - let labels = labels.clone(); std::thread::Builder::new().name(String::from("isolate-") + deployment.id.as_str()).spawn(move || { handle.block_on(async move { - increment_gauge!("lagon_isolates", 1.0, &labels); + increment_gauge!("lagon_isolates", 1.0, "deployment" => deployment.id.clone(), "function" => deployment.function_id.clone()); info!(deployment = deployment.id, function = deployment.function_id, request = request_id_handle; "Creating new isolate"); let code = deployment.get_code().unwrap_or_else(|error| { @@ -240,7 +229,6 @@ async fn handle_request( let labels = [ ("deployment", metadata.0.clone()), ("function", metadata.1.clone()), - ("region", REGION.clone()), ]; decrement_gauge!("lagon_isolates", 1.0, &labels); @@ -252,7 +240,6 @@ async fn handle_request( let labels = [ ("deployment", metadata.0.clone()), ("function", metadata.1.clone()), - ("region", REGION.clone()), ]; histogram!( @@ -290,7 +277,6 @@ async fn handle_request( let function_id = function_id.clone(); let deployment_id = deployment_id.clone(); let request_id = request_id.clone(); - let labels = labels.clone(); async move { match event { @@ -304,7 +290,7 @@ async fn handle_request( .write(&RequestRow { function_id, deployment_id, - region: REGION.clone(), + region: get_region().clone(), bytes_in, bytes_out: bytes as u32, cpu_time_micros, @@ -321,32 +307,15 @@ async fn handle_request( function_id, deployment_id, &request_id, - &labels, inserters, ) .await; } ResponseEvent::UnexpectedStreamResult(result) => { - handle_error( - result, - function_id, - deployment_id, - &request_id, - &labels, - inserters, - ) - .await; + handle_error(result, function_id, deployment_id, &request_id, inserters).await; } ResponseEvent::LimitsReached(result) | ResponseEvent::Error(result) => { - handle_error( - result, - function_id, - deployment_id, - &request_id, - &labels, - inserters, - ) - .await; + handle_error(result, function_id, deployment_id, &request_id, inserters).await; } } @@ -453,7 +422,7 @@ where .map_or_else(String::new, |metadata| metadata.0.clone()), level: log.0, message: log.1, - region: REGION.clone(), + region: get_region().clone(), timestamp: UNIX_EPOCH.elapsed().unwrap().as_secs() as u32, }) .await diff --git a/crates/serverless_logger/src/lib.rs b/crates/serverless_logger/src/lib.rs index d44dab1d9..29dc946ca 100644 --- a/crates/serverless_logger/src/lib.rs +++ b/crates/serverless_logger/src/lib.rs @@ -1,13 +1,12 @@ use axiom_rs::Client; use chrono::prelude::Local; use flume::Sender; -use serde_json::{json, Value}; -use std::sync::{Arc, RwLock}; - use log::{ - as_debug, kv::source::as_map, set_boxed_logger, set_max_level, Level, LevelFilter, Log, + as_serde, kv::source::as_map, set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record, SetLoggerError, }; +use serde_json::{json, Value}; +use std::sync::{Arc, RwLock}; struct SimpleLogger { tx: Arc>>>, @@ -54,7 +53,7 @@ impl Log for SimpleLogger { Local::now(), record.level(), record.args(), - as_debug!(metadata), + as_serde!(metadata), ); // Axiom is optional, so tx can have no listeners diff --git a/crates/wpt-runner/Cargo.toml b/crates/wpt-runner/Cargo.toml index dac3b552d..9ccaefe5c 100644 --- a/crates/wpt-runner/Cargo.toml +++ b/crates/wpt-runner/Cargo.toml @@ -10,5 +10,4 @@ lagon-runtime-http = { path = "../runtime_http" } lagon-runtime-isolate = { path = "../runtime_isolate" } flume = "0.10.14" console = "0.15.7" -once_cell = "1.17.1" hyper = { version = "0.14.26", features = ["server"] } diff --git a/crates/wpt-runner/src/main.rs b/crates/wpt-runner/src/main.rs index c81cfc946..5ce6b3483 100644 --- a/crates/wpt-runner/src/main.rs +++ b/crates/wpt-runner/src/main.rs @@ -3,12 +3,11 @@ use hyper::{http::Request, Body}; use lagon_runtime::{options::RuntimeOptions, Runtime}; use lagon_runtime_http::RunResult; use lagon_runtime_isolate::{options::IsolateOptions, Isolate, IsolateEvent, IsolateRequest}; -use once_cell::sync::Lazy; use std::{ env, fs, path::{Path, PathBuf}, process::exit, - sync::Mutex, + sync::{Mutex, OnceLock}, }; use tokio::runtime::Handle; @@ -43,14 +42,9 @@ const SUPPORT_FORMDATA: &str = include_str!("../../../tools/wpt/FileAPI/support/send-file-formdata-helper.js"); const STREAM_DISTURBED_UTIL: &str = include_str!("../../../tools/wpt/fetch/api/response/response-stream-disturbed-util.js"); +const TEST_HARNESS: &str = include_str!("../../../tools/wpt/resources/testharness.js"); -static RESULT: Lazy> = Lazy::new(|| Mutex::new((0, 0, 0))); -static TEST_HARNESS: Lazy = Lazy::new(|| { - include_str!("../../../tools/wpt/resources/testharness.js") - .to_owned() - .replace("})(self);", "})(globalThis);") - .replace("debug: false", "debug: true") -}); +static RESULT: OnceLock> = OnceLock::new(); const SKIP_TESTS: [&str; 22] = [ // response @@ -122,7 +116,9 @@ export function handler() {{ {code} return new Response() }}", - TEST_HARNESS.as_str(), + TEST_HARNESS + .replace("})(self);", "})(globalThis);") + .replace("debug: false", "debug: true"), ) .replace("self.", "globalThis."); @@ -142,14 +138,16 @@ export function handler() {{ while let Ok(log) = logs_receiver.recv_async().await { let content = log.1; + let result = RESULT.get_or_init(|| Mutex::new((0, 0, 0))); + if content.starts_with("TEST DONE 0") { - RESULT.lock().unwrap().1 += 1; + result.lock().unwrap().1 += 1; println!("{}", style(content).green()); } else if content.starts_with("TEST DONE 1") { - RESULT.lock().unwrap().2 += 1; + result.lock().unwrap().2 += 1; println!("{}", style(content).red()); } else if content.starts_with("TEST START") { - RESULT.lock().unwrap().0 += 1; + result.lock().unwrap().0 += 1; } else { // println!("{}", content); } @@ -223,23 +221,25 @@ async fn main() { test_directory(Path::new("../../tools/wpt/urlpattern")).await; } - let result = RESULT.lock().unwrap(); - println!(); - println!( - "{} tests, {} passed, {} failed ({} not completed)", - result.0, - style(result.1.to_string()).green(), - style(result.2.to_string()).red(), - result.0 - (result.1 + result.2) - ); - - if result.2 == 0 { - println!(" -> 100% conformance"); - } else { + if let Some(result) = RESULT.get() { + let result = result.lock().unwrap(); + println!(); println!( - " -> {}% conformance", - (result.1 * 100) / (result.1 + result.2) + "{} tests, {} passed, {} failed ({} not completed)", + result.0, + style(result.1.to_string()).green(), + style(result.2.to_string()).red(), + result.0 - (result.1 + result.2) ); + + if result.2 == 0 { + println!(" -> 100% conformance"); + } else { + println!( + " -> {}% conformance", + (result.1 * 100) / (result.1 + result.2) + ); + } } runtime.dispose();