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
+10 -1
View File
@@ -30,6 +30,7 @@ async fn main() -> anyhow::Result<()> {
let content_branch = std::env::var("CONTENT_BRANCH").unwrap_or_else(|_| "main".to_string());
let questions = content::load_questions_from_gitea(&content_repo, &content_branch, "questions").await?;
tracing::info!(count = questions.len(), repo = %content_repo, branch = %content_branch, "loaded content");
let questions = Arc::new(arc_swap::ArcSwap::from_pointee(questions));
let nats_url =
std::env::var("NATS_URL").unwrap_or_else(|_| "nats://127.0.0.1:4222".to_string());
@@ -56,11 +57,19 @@ async fn main() -> anyhow::Result<()> {
tracing::warn!("GARAGE_* env vars not set - file upload fields will fail closed");
}
tokio::spawn(content::watch_for_reload(
nats.clone(),
content_repo,
content_branch,
"questions".to_string(),
questions.clone(),
));
let state = AppState {
leptos_options: leptos_options.clone(),
nats,
jetstream,
questions: std::sync::Arc::new(questions),
questions,
oidc: oidc_state,
garage,
};