From ff83ce0ca13708f02b677a1aa4be7655d67e5760 Mon Sep 17 00:00:00 2001 From: Roman Kivalin Date: Fri, 17 Apr 2026 21:28:36 +0200 Subject: [PATCH] Fix solver startup race condition with Notify The HTTP-01 and TLS-ALPN-01 solvers used tokio::sync::Notify to signal that the server task had started. If the spawned task called notify_waiters() before the caller registered with notified(), the notification was lost and the solver would hang indefinitely. Fix by creating the Notified future before spawning the task. Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 2 ++ debian/changelog | 2 +- src/solver/http01.rs | 5 ++++- src/solver/tls_alpn01.rs | 5 ++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5057ef2..02037d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ### Fixes +- Fix HTTP-01 and TLS-ALPN-01 solvers sometimes hanging on startup due to a `Notify` race condition + ### Changes ## 0.7.0 (2026-04-17) diff --git a/debian/changelog b/debian/changelog index 1befed7..64d3c0e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ certforge (0.8.0-1) unstable; urgency=low - * No changes + * Fix HTTP-01 and TLS-ALPN-01 solvers hanging on startup -- Roman Kivalin Thu, 17 Apr 2026 00:00:00 +0000 diff --git a/src/solver/http01.rs b/src/solver/http01.rs index be64931..84f28eb 100644 --- a/src/solver/http01.rs +++ b/src/solver/http01.rs @@ -61,6 +61,9 @@ impl Http01StandaloneSolver { let tokens = self.tokens.clone(); let started = self.server_started.clone(); + // Register the listener before spawning so we don't miss the notification + let notified = self.server_started.notified(); + let handle = tokio::spawn(async move { started.notify_waiters(); // Spawn an accept loop for each bound listener @@ -93,7 +96,7 @@ impl Http01StandaloneSolver { } }); - self.server_started.notified().await; + notified.await; Ok::<_, Error>(handle) }).await; diff --git a/src/solver/tls_alpn01.rs b/src/solver/tls_alpn01.rs index 9aa74ca..a67430f 100644 --- a/src/solver/tls_alpn01.rs +++ b/src/solver/tls_alpn01.rs @@ -77,6 +77,9 @@ impl TlsAlpn01Solver { let acceptor = TlsAcceptor::from(tls_config); + // Register the listener before spawning so we don't miss the notification + let notified = self.server_started.notified(); + let handle = tokio::spawn(async move { started.notify_waiters(); let mut handles = Vec::new(); @@ -99,7 +102,7 @@ impl TlsAlpn01Solver { } }); - self.server_started.notified().await; + notified.await; Ok::<_, Error>(handle) }).await;