Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006) | 1 | //! g1t-wide pauses (billing's `platform_pause`; docs/SPEND-GUARDRAILS.md), |
| 2 | //! read cheaply: one call to billing per isolate every 30 seconds at most, | |
| 3 | //! never a database read per request. | |
| 4 | //! | |
| 5 | //! When billing cannot say, nothing is paused: a pause is a brake staff | |
| 6 | //! (or billing's usage watcher) pull on purpose, and a billing outage must | |
| 7 | //! not stop schedules and indexing everywhere. The failure is kept for the | |
| 8 | //! same 30 seconds, so an outage is not asked about on every request. | |
| 9 | ||
| 10 | use std::cell::RefCell; | |
| 11 | ||
| 12 | use g1t_contracts::billing::{PauseLevel, PlatformPause}; | |
| 13 | use worker::Fetcher; | |
| 14 | ||
| 15 | /// How long an answer is kept in the isolate. | |
| 16 | pub const KEEP_MS: u64 = 30_000; | |
| 17 | ||
| 18 | thread_local! { | |
| 19 | static KEPT: RefCell<Option<(PlatformPause, u64)>> = const { RefCell::new(None) }; | |
| 20 | } | |
| 21 | ||
| 22 | /// A kept answer, while it is fresh. | |
| 23 | fn fresh(kept: Option<(PlatformPause, u64)>, now: u64) -> Option<PlatformPause> { | |
| 24 | kept.filter(|(_, until)| *until > now).map(|(pause, _)| pause) | |
| 25 | } | |
| 26 | ||
| 27 | /// Whether `level` is paused, through the billing service's binding. | |
| 28 | pub async fn paused(billing: &Fetcher, level: PauseLevel) -> bool { | |
| 29 | current(billing).await.is(level) | |
| 30 | } | |
| 31 | ||
| 32 | /// Every level, kept for `KEEP_MS`. Nothing paused when billing cannot say. | |
| 33 | pub async fn current(billing: &Fetcher) -> PlatformPause { | |
| 34 | let now = crate::now_ms(); | |
| 35 | if let Some(pause) = KEPT.with(|kept| fresh(*kept.borrow(), now)) { | |
| 36 | return pause; | |
| 37 | } | |
| 38 | let pause = match crate::call::<_, PlatformPause>(billing, "platform_pause", &serde_json::json!({})).await { | |
| 39 | Ok(pause) => pause, | |
| 40 | Err(error) => { | |
| 41 | worker::console_error!("platform pause unreadable, so nothing is paused: {error}"); | |
| 42 | PlatformPause::default() | |
| 43 | } | |
| 44 | }; | |
| 45 | KEPT.with(|kept| *kept.borrow_mut() = Some((pause, now + KEEP_MS))); | |
| 46 | pause | |
| 47 | } | |
| 48 | ||
| 49 | #[cfg(test)] | |
| 50 | mod tests { | |
| 51 | use super::*; | |
| 52 | ||
| 53 | #[test] | |
| 54 | fn an_answer_is_kept_thirty_seconds() { | |
| 55 | let paused = PlatformPause { schedules: true, ..PlatformPause::default() }; | |
| 56 | assert_eq!(fresh(Some((paused, 1_000 + KEEP_MS)), 1_000), Some(paused)); | |
| 57 | assert_eq!(fresh(Some((paused, 1_000 + KEEP_MS)), 1_000 + KEEP_MS), None); | |
| 58 | assert_eq!(fresh(None, 0), None); | |
| 59 | } | |
| 60 | ||
| 61 | #[test] | |
| 62 | fn an_unread_pause_pauses_nothing() { | |
| 63 | let none = PlatformPause::default(); | |
| 64 | assert!(PauseLevel::ALL.into_iter().all(|level| !none.is(level))); | |
| 65 | assert!(!none.any()); | |
| 66 | } | |
| 67 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.