Hot-reload content on a NATS trigger instead of requiring a restart
Deploy / deploy (push) Successful in 29s

questions is now Arc<ArcSwap<HashMap<...>>> - readers do a lock-free
atomic load (state.questions.load().get(&id).cloned()), never blocking
on or blocked by a reload. content::watch_for_reload subscribes to
portal.content.reload (published by the questions repo's own CI after
it lints a push - see that repo's lint-and-reload.yml) and swaps in a
freshly re-fetched HashMap on each message. A fetch/parse failure logs
and keeps serving the last-good content rather than clearing it.
This commit is contained in:
Bendik Aagaard Lynghaug
2026-08-05 07:20:40 +02:00
parent b0086b2ed9
commit 18025bf870
8 changed files with 74 additions and 8 deletions
+6 -1
View File
@@ -2,6 +2,7 @@
pub mod oidc;
use arc_swap::ArcSwap;
use axum::extract::FromRef;
use leptos::prelude::LeptosOptions;
use std::collections::HashMap;
@@ -16,7 +17,11 @@ pub struct AppState {
/// JetStream context - source of every NATS KV bucket this app
/// reads/writes (applicants, and whatever a `ResourceSpec` names).
pub jetstream: async_nats::jetstream::Context,
pub questions: Arc<HashMap<String, Question>>,
/// Swapped out wholesale on a `content::CONTENT_RELOAD_SUBJECT`
/// message (see `content::watch_for_reload`) - readers never hold
/// a lock, just an atomic pointer load, so a reload never blocks or
/// is blocked by an in-flight request.
pub questions: Arc<ArcSwap<HashMap<String, Question>>>,
pub oidc: Arc<oidc::Oidc>,
/// `None` when `GARAGE_*` env vars aren't set - uploads are the one
/// optional feature, everything else works without Garage.