Skip to main content

headless_lms_models/
suotar_endpoint_rate_limits.rs

1//! The last limiter state the worker reported per rate-limited Suotar endpoint. The worker keeps the
2//! live state in memory; this copy is only for the dashboard, which runs in another process. The
3//! breakers are in [`crate::suotar_circuit_breakers`].
4
5use utoipa::ToSchema;
6
7use crate::prelude::*;
8use crate::suotar_api_calls::SuotarEndpoint;
9
10/// One endpoint's limiter as the worker last reported it.
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
12pub struct SuotarEndpointRateLimit {
13    pub endpoint: SuotarEndpoint,
14    /// When the worker last reported the state.
15    pub updated_at: DateTime<Utc>,
16    /// The share of the full rate allowed, from 0.1 up to 1.
17    pub rate_share: f32,
18    /// Items per minute, or requests per minute for `list_by_course`.
19    pub full_rate_per_minute: i32,
20    /// Items, or requests, that could go out right now.
21    pub available: i32,
22}
23
24/// What the worker reports for one endpoint; [`SuotarEndpointRateLimit`] without the report time.
25#[derive(Debug, Clone, PartialEq)]
26pub struct SuotarEndpointRateLimitReport {
27    pub endpoint: SuotarEndpoint,
28    pub rate_share: f32,
29    pub full_rate_per_minute: i32,
30    pub available: i32,
31}
32
33/// Replaces the endpoint's reported limiter state.
34pub async fn upsert(
35    conn: &mut PgConnection,
36    state: &SuotarEndpointRateLimitReport,
37) -> ModelResult<()> {
38    sqlx::query!(
39        r#"
40INSERT INTO suotar_endpoint_rate_limits (
41    endpoint,
42    rate_share,
43    full_rate_per_minute,
44    available
45  )
46VALUES ($1, $2, $3, $4) ON CONFLICT (endpoint) DO
47UPDATE
48SET rate_share = EXCLUDED.rate_share,
49  full_rate_per_minute = EXCLUDED.full_rate_per_minute,
50  available = EXCLUDED.available
51        "#,
52        state.endpoint as SuotarEndpoint,
53        state.rate_share,
54        state.full_rate_per_minute,
55        state.available,
56    )
57    .execute(conn)
58    .await?;
59    Ok(())
60}
61
62/// Every endpoint's last reported limiter state, for the dashboard.
63pub async fn get_all(conn: &mut PgConnection) -> ModelResult<Vec<SuotarEndpointRateLimit>> {
64    let res = sqlx::query_as!(
65        SuotarEndpointRateLimit,
66        r#"
67SELECT endpoint,
68  updated_at,
69  rate_share,
70  full_rate_per_minute,
71  available
72FROM suotar_endpoint_rate_limits
73ORDER BY endpoint
74        "#,
75    )
76    .fetch_all(conn)
77    .await?;
78    Ok(res)
79}