From 226c318e4ad416ab083fb0978f1494f996f94e4c Mon Sep 17 00:00:00 2001 From: Peter Bokor Date: Thu, 1 Aug 2024 23:33:56 +0200 Subject: [PATCH] prepare PR 1 --- .../src/from_sdl_config.rs | 4 +- engine/crates/engine/response/src/lib.rs | 1 + engine/crates/parser-sdl/src/federation.rs | 69 ++++++++++++++++--- .../src/rules/subgraph_directive.rs | 24 +++---- engine/crates/runtime-local/src/lib.rs | 1 + gateway/crates/config/src/entity_caching.rs | 54 ++++++++++++++- 6 files changed, 127 insertions(+), 26 deletions(-) diff --git a/engine/crates/engine-config-builder/src/from_sdl_config.rs b/engine/crates/engine-config-builder/src/from_sdl_config.rs index 7102956d3d..2540032e32 100644 --- a/engine/crates/engine-config-builder/src/from_sdl_config.rs +++ b/engine/crates/engine-config-builder/src/from_sdl_config.rs @@ -44,7 +44,7 @@ pub fn build_with_sdl_config(config: &FederatedGraphConfig, graph: FederatedGrap rate_limit: context.rate_limit, timeout: config.timeout, entity_caching: match config.entity_caching { - EntityCachingConfig::Enabled { ttl } => EntityCaching::Enabled { ttl }, + EntityCachingConfig::Enabled { ttl, .. } => EntityCaching::Enabled { ttl }, _ => EntityCaching::Disabled, }, }) @@ -211,7 +211,7 @@ impl<'a> BuildContext<'a> { retry, entity_caching: entity_caching.as_ref().map(|config| match config { EntityCachingConfig::Disabled => EntityCaching::Disabled, - EntityCachingConfig::Enabled { ttl } => EntityCaching::Enabled { ttl: *ttl }, + EntityCachingConfig::Enabled { ttl, .. } => EntityCaching::Enabled { ttl: *ttl }, }), }, ); diff --git a/engine/crates/engine/response/src/lib.rs b/engine/crates/engine/response/src/lib.rs index 3a27b13773..a5479beae9 100644 --- a/engine/crates/engine/response/src/lib.rs +++ b/engine/crates/engine/response/src/lib.rs @@ -24,6 +24,7 @@ mod streaming; pub struct GraphqlOperationAnalyticsAttributes { pub name: Option, pub r#type: common_types::OperationType, + #[serde(default)] pub used_fields: String, } diff --git a/engine/crates/parser-sdl/src/federation.rs b/engine/crates/parser-sdl/src/federation.rs index 0fa53b28b4..2831a96748 100644 --- a/engine/crates/parser-sdl/src/federation.rs +++ b/engine/crates/parser-sdl/src/federation.rs @@ -61,20 +61,62 @@ pub enum EntityCachingConfig { Disabled, Enabled { ttl: Option, + storage: EntityCacheStorage, }, } +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] +pub enum EntityCacheStorage { + #[default] + Memory, + Redis(RedisConfig), +} + impl From for EntityCachingConfig { fn from(config: gateway_config::EntityCachingConfig) -> Self { match (config.enabled, config.ttl) { (Some(false), _) => EntityCachingConfig::Disabled, - (Some(true), ttl) => EntityCachingConfig::Enabled { ttl }, - (_, Some(ttl)) => EntityCachingConfig::Enabled { ttl: Some(ttl) }, + (Some(true), ttl) => EntityCachingConfig::Enabled { + ttl, + storage: entity_cache_storage(config.storage, config.redis), + }, + (_, Some(ttl)) => EntityCachingConfig::Enabled { + ttl: Some(ttl), + storage: entity_cache_storage(config.storage, config.redis), + }, _ => EntityCachingConfig::Disabled, } } } +fn entity_cache_storage( + storage: gateway_config::EntityCachingStorage, + redis: Option, +) -> EntityCacheStorage { + match storage { + gateway_config::EntityCachingStorage::Memory => EntityCacheStorage::Memory, + gateway_config::EntityCachingStorage::Redis => EntityCacheStorage::Redis(redis.unwrap_or_default().into()), + } +} + +impl From for RedisConfig { + fn from(value: gateway_config::EntityCachingRedisConfig) -> Self { + let gateway_config::EntityCachingRedisConfig { url, key_prefix, tls } = value; + RedisConfig { + url, + key_prefix, + tls: tls.map(Into::into), + } + } +} + +impl From for RedisTlsConfig { + fn from(value: gateway_config::EntityCachingRedisTlsConfig) -> Self { + let gateway_config::EntityCachingRedisTlsConfig { cert, key, ca } = value; + RedisTlsConfig { cert, key, ca } + } +} + impl From<(String, ConnectorHeaderValue)> for SubgraphHeaderRule { fn from((name, value): (String, ConnectorHeaderValue)) -> Self { match value { @@ -100,7 +142,7 @@ pub struct GraphRateLimit { pub struct RateLimitConfig { pub global: Option, pub storage: RateLimitStorage, - pub redis: RateLimitRedisConfig, + pub redis: RedisConfig, } impl From for RateLimitConfig { @@ -131,7 +173,7 @@ impl From for RateLimitStorage { } } -impl From for RateLimitRedisConfig { +impl From for RedisConfig { fn from(value: gateway_config::RateLimitRedisConfig) -> Self { Self { url: value.url, @@ -141,7 +183,7 @@ impl From for RateLimitRedisConfig { } } -impl From for RateLimitRedisTlsConfig { +impl From for RedisTlsConfig { fn from(value: gateway_config::RateLimitRedisTlsConfig) -> Self { Self { cert: value.cert, @@ -158,14 +200,14 @@ pub enum RateLimitStorage { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct RateLimitRedisConfig { +pub struct RedisConfig { pub url: url::Url, pub key_prefix: String, - pub tls: Option, + pub tls: Option, } #[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] -pub struct RateLimitRedisTlsConfig { +pub struct RedisTlsConfig { pub cert: Option, pub key: Option, pub ca: Option, @@ -201,7 +243,8 @@ mod tests { assert_eq!( EntityCachingConfig::from(config.entity_caching), EntityCachingConfig::Enabled { - ttl: Some(Duration::from_secs(60)) + ttl: Some(Duration::from_secs(60)), + storage: Default::default(), } ) } @@ -218,7 +261,8 @@ mod tests { assert_eq!( EntityCachingConfig::from(config.subgraphs.remove("products").unwrap().entity_caching.unwrap()), EntityCachingConfig::Enabled { - ttl: Some(Duration::from_secs(60)) + ttl: Some(Duration::from_secs(60)), + storage: Default::default() } ) } @@ -234,7 +278,10 @@ mod tests { assert_eq!( EntityCachingConfig::from(config.subgraphs.remove("products").unwrap().entity_caching.unwrap()), - EntityCachingConfig::Enabled { ttl: None } + EntityCachingConfig::Enabled { + ttl: None, + storage: Default::default() + } ) } diff --git a/engine/crates/parser-sdl/src/rules/subgraph_directive.rs b/engine/crates/parser-sdl/src/rules/subgraph_directive.rs index fe80024a51..7011705b59 100644 --- a/engine/crates/parser-sdl/src/rules/subgraph_directive.rs +++ b/engine/crates/parser-sdl/src/rules/subgraph_directive.rs @@ -190,18 +190,18 @@ impl Visitor<'_> for SubgraphDirectiveVisitor { subgraph.development_url = Some(url.to_string()) } - if let Some(enabled) = directive.entity_caching_enabled { - if enabled { - subgraph.entity_caching = Some(EntityCachingConfig::Enabled { ttl: None }); - } else { - subgraph.entity_caching = Some(EntityCachingConfig::Disabled); - } - } - - if let Some(ttl) = directive.entity_caching_ttl { - // If there's a ttl we always enable - subgraph.entity_caching = Some(EntityCachingConfig::Enabled { ttl: Some(ttl) }); - } + subgraph.entity_caching = match (directive.entity_caching_enabled, directive.entity_caching_ttl) { + (Some(false), _) => Some(EntityCachingConfig::Disabled), + (Some(true), ttl) => Some(EntityCachingConfig::Enabled { + ttl, + storage: Default::default(), + }), + (_, Some(ttl)) => Some(EntityCachingConfig::Enabled { + ttl: Some(ttl), + storage: Default::default(), + }), + _ => None, + }; subgraph.header_rules.extend( directive diff --git a/engine/crates/runtime-local/src/lib.rs b/engine/crates/runtime-local/src/lib.rs index 8da63e4c57..f6043c3f22 100644 --- a/engine/crates/runtime-local/src/lib.rs +++ b/engine/crates/runtime-local/src/lib.rs @@ -8,6 +8,7 @@ mod kv; mod log; mod pg; pub mod rate_limiting; +#[cfg(feature = "redis")] pub mod redis; mod ufd_invoker; diff --git a/gateway/crates/config/src/entity_caching.rs b/gateway/crates/config/src/entity_caching.rs index d5be7e11f5..ccb199a80f 100644 --- a/gateway/crates/config/src/entity_caching.rs +++ b/gateway/crates/config/src/entity_caching.rs @@ -1,10 +1,62 @@ -use std::time::Duration; +use std::{path::PathBuf, time::Duration}; #[derive(Debug, Default, serde::Deserialize, Clone, PartialEq)] pub struct EntityCachingConfig { pub enabled: Option, + #[serde(default)] + pub storage: EntityCachingStorage, + + #[serde(default)] + pub redis: Option, + /// The ttl to store cache entries with. Defaults to 60s #[serde(deserialize_with = "duration_str::deserialize_option_duration", default)] pub ttl: Option, } + +#[derive(Debug, Clone, Default, PartialEq, serde::Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum EntityCachingStorage { + #[default] + Memory, + Redis, +} + +#[derive(Debug, Clone, PartialEq, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct EntityCachingRedisConfig { + #[serde(default = "EntityCachingRedisConfig::default_url")] + pub url: url::Url, + #[serde(default = "EntityCachingRedisConfig::default_key_prefix")] + pub key_prefix: String, + pub tls: Option, +} + +impl Default for EntityCachingRedisConfig { + fn default() -> Self { + Self { + url: Self::default_url(), + key_prefix: Self::default_key_prefix(), + tls: None, + } + } +} + +impl EntityCachingRedisConfig { + fn default_url() -> url::Url { + url::Url::parse("redis://localhost:6379").expect("must be correct") + } + + fn default_key_prefix() -> String { + String::from("grafbase-cache") + } +} + +#[derive(Debug, Clone, PartialEq, Default, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct EntityCachingRedisTlsConfig { + pub cert: Option, + pub key: Option, + pub ca: Option, +}