-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pr 4 #4
base: pr-3
Are you sure you want to change the base?
Pr 4 #4
Changes from all commits
cdba43c
04a9cc5
b82449d
de39e03
8945210
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,10 @@ use grafbase_telemetry::{ | |
gql_response_status::{GraphqlResponseStatus, SubgraphResponseStatus}, | ||
span::{GqlRecorderSpanExt, GRAFBASE_TARGET}, | ||
}; | ||
use runtime::fetch::{FetchRequest, FetchResponse}; | ||
use runtime::{ | ||
fetch::{FetchRequest, FetchResponse}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ⚡ Suggestion |
||
rate_limiting::RateLimitKey, | ||
}; | ||
use schema::sources::graphql::{GraphqlEndpointId, GraphqlEndpointWalker}; | ||
use tower::retry::budget::Budget; | ||
use tracing::Span; | ||
|
@@ -13,7 +16,7 @@ use web_time::Duration; | |
use crate::{ | ||
execution::{ExecutionContext, ExecutionError, ExecutionResult}, | ||
response::SubgraphResponse, | ||
RateLimitContext, Runtime, | ||
Runtime, | ||
}; | ||
|
||
pub trait ResponseIngester: Send { | ||
|
@@ -130,7 +133,7 @@ async fn rate_limited_fetch<'ctx, R: Runtime>( | |
ctx.engine | ||
.runtime | ||
.rate_limiter() | ||
.limit(&RateLimitContext::Subgraph(subgraph.name())) | ||
.limit(&RateLimitKey::Subgraph(subgraph.name().into())) | ||
.await?; | ||
|
||
ctx.engine | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
use std::net::IpAddr; | ||
use std::num::NonZeroU32; | ||
use std::sync::Arc; | ||
use std::{collections::HashMap, sync::RwLock}; | ||
|
@@ -7,69 +6,48 @@ use futures_util::future::BoxFuture; | |
use futures_util::FutureExt; | ||
use governor::Quota; | ||
use grafbase_telemetry::span::GRAFBASE_TARGET; | ||
use serde_json::Value; | ||
|
||
use http::{HeaderName, HeaderValue}; | ||
use runtime::rate_limiting::{Error, GraphRateLimit, KeyedRateLimitConfig, RateLimiter, RateLimiterContext}; | ||
use tokio::sync::mpsc; | ||
use runtime::rate_limiting::{Error, GraphRateLimit, RateLimitKey, RateLimiter, RateLimiterContext}; | ||
use tokio::sync::watch; | ||
|
||
pub struct RateLimitingContext(pub String); | ||
|
||
impl RateLimiterContext for RateLimitingContext { | ||
fn header(&self, _name: HeaderName) -> Option<&HeaderValue> { | ||
None | ||
} | ||
|
||
fn graphql_operation_name(&self) -> Option<&str> { | ||
None | ||
} | ||
|
||
fn ip(&self) -> Option<IpAddr> { | ||
None | ||
} | ||
|
||
fn jwt_claim(&self, _key: &str) -> Option<&Value> { | ||
None | ||
} | ||
|
||
fn key(&self) -> Option<&str> { | ||
Some(&self.0) | ||
} | ||
} | ||
type Limits = HashMap<RateLimitKey<'static>, GraphRateLimit>; | ||
type Limiters = HashMap<RateLimitKey<'static>, governor::DefaultKeyedRateLimiter<usize>>; | ||
|
||
pub struct InMemoryRateLimiter { | ||
limiters: Arc<RwLock<HashMap<String, governor::DefaultKeyedRateLimiter<usize>>>>, | ||
limiters: Arc<RwLock<Limiters>>, | ||
} | ||
|
||
impl InMemoryRateLimiter { | ||
pub fn runtime( | ||
config: KeyedRateLimitConfig, | ||
mut updates: mpsc::Receiver<HashMap<String, GraphRateLimit>>, | ||
) -> RateLimiter { | ||
pub fn runtime(mut updates: watch::Receiver<Limits>) -> RateLimiter { | ||
let mut limiters = HashMap::new(); | ||
|
||
// add subgraph rate limiting configuration | ||
for (name, config) in config.rate_limiting_configs { | ||
let Some(limiter) = create_limiter(config) else { | ||
for (name, config) in updates.borrow_and_update().iter() { | ||
let Some(limiter) = create_limiter(*config) else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ⚡ Suggestion |
||
continue; | ||
}; | ||
|
||
limiters.insert(name.to_string(), limiter); | ||
limiters.insert(name.clone(), limiter); | ||
} | ||
|
||
let limiters = Arc::new(RwLock::new(limiters)); | ||
let limiters_copy = limiters.clone(); | ||
let limiters_copy = Arc::downgrade(&limiters); | ||
|
||
tokio::spawn(async move { | ||
while let Some(updates) = updates.recv().await { | ||
let mut limiters = limiters_copy.write().unwrap(); | ||
while let Ok(()) = updates.changed().await { | ||
let Some(limiters) = limiters_copy.upgrade() else { | ||
break; | ||
}; | ||
|
||
let mut limiters = limiters.write().unwrap(); | ||
limiters.clear(); | ||
|
||
for (name, config) in updates { | ||
let Some(limiter) = create_limiter(config) else { | ||
for (name, config) in updates.borrow_and_update().iter() { | ||
let Some(limiter) = create_limiter(*config) else { | ||
continue; | ||
}; | ||
|
||
limiters.insert(name.to_string(), limiter); | ||
limiters.insert(name.clone(), limiter); | ||
} | ||
} | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚡ Suggestion
Consider handling the case where
k
does not match any of the expected variants. This will help prevent potential runtime errors if an unexpected value is encountered.