diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-23 15:41:32 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-23 15:41:32 +0000 |
| commit | c54ce061d6d278cce8362d5af085808ca60c239b (patch) | |
| tree | ec967d6195d9f7ec4f061449596611afe3a0950f /src/main.rs | |
| parent | e0ad39a489b3398f8208713bf728db0cb11475b0 (diff) | |
| parent | 113928aa84894ea8f65c247d9987527e792b32a9 (diff) | |
feat: announcement purgatory
Extends purgatory to hold repository announcements until git data arrives,
preventing empty repositories from being served to clients.
When an announcement is received, a bare repo is created immediately and the
announcement is held in purgatory. It is only promoted and served once a git
push confirms real content exists. If no push arrives before expiry, the bare
repo is deleted and the announcement is silently discarded.
Key behaviours:
- Soft expiry: announcements are hidden from clients but kept alive while git
pushes are in progress, reviving on successful push
- Expiry is extended when a matching state event or git push is observed
- NIP-09 deletion events remove announcements from purgatory
- Purgatory state (announcements, state events, PR events, expired set) is
persisted to disk on graceful shutdown and restored on startup, with elapsed
downtime subtracted from expiry deadlines
- Purgatory announcements drive StateOnly sync in the sync system so state
events are fetched from listed relays before promotion
- SyncLevel added to RepoSyncIndex to distinguish purgatory repos (StateOnly)
from promoted repos (Full L2+L3 sync)
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/src/main.rs b/src/main.rs index dd2c903..bf3aefb 100644 --- a/src/main.rs +++ b/src/main.rs | |||
| @@ -130,7 +130,9 @@ async fn main() -> Result<()> { | |||
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | // Get a reference to the rejected events index for shutdown persistence | 132 | // Get a reference to the rejected events index for shutdown persistence |
| 133 | // and for the HTTP server's git push path (hot-cache re-processing) | ||
| 133 | let shutdown_rejected_index = sync_manager.rejected_events_index(); | 134 | let shutdown_rejected_index = sync_manager.rejected_events_index(); |
| 135 | let http_rejected_index = shutdown_rejected_index.clone(); | ||
| 134 | 136 | ||
| 135 | tokio::spawn(async move { | 137 | tokio::spawn(async move { |
| 136 | sync_manager.run().await; | 138 | sync_manager.run().await; |
| @@ -142,11 +144,11 @@ async fn main() -> Result<()> { | |||
| 142 | let mut interval = tokio::time::interval(Duration::from_secs(60)); | 144 | let mut interval = tokio::time::interval(Duration::from_secs(60)); |
| 143 | loop { | 145 | loop { |
| 144 | interval.tick().await; | 146 | interval.tick().await; |
| 145 | let (state_removed, pr_removed) = cleanup_purgatory.cleanup(); | 147 | let (announcement_removed, state_removed, pr_removed) = cleanup_purgatory.cleanup(); |
| 146 | if state_removed > 0 || pr_removed > 0 { | 148 | if announcement_removed > 0 || state_removed > 0 || pr_removed > 0 { |
| 147 | info!( | 149 | info!( |
| 148 | "Purgatory cleanup: removed {} state events, {} PR events", | 150 | "Purgatory cleanup: removed {} announcements, {} state events, {} PR events", |
| 149 | state_removed, pr_removed | 151 | announcement_removed, state_removed, pr_removed |
| 150 | ); | 152 | ); |
| 151 | } | 153 | } |
| 152 | } | 154 | } |
| @@ -206,12 +208,15 @@ async fn main() -> Result<()> { | |||
| 206 | // Start HTTP server with integrated relay and database | 208 | // Start HTTP server with integrated relay and database |
| 207 | info!("Starting HTTP server on {}", config.bind_address); | 209 | info!("Starting HTTP server on {}", config.bind_address); |
| 208 | 210 | ||
| 211 | // Wrap write_policy in Arc for sharing between HTTP server connections | ||
| 212 | let http_write_policy = Arc::new(relay_with_db.write_policy.clone()); | ||
| 213 | |||
| 209 | // Run server until shutdown signal, then cleanup | 214 | // Run server until shutdown signal, then cleanup |
| 210 | #[cfg(unix)] | 215 | #[cfg(unix)] |
| 211 | { | 216 | { |
| 212 | use tokio::signal::unix::{signal, SignalKind}; | 217 | use tokio::signal::unix::{signal, SignalKind}; |
| 213 | let mut sigterm = signal(SignalKind::terminate())?; | 218 | let mut sigterm = signal(SignalKind::terminate())?; |
| 214 | 219 | ||
| 215 | tokio::select! { | 220 | tokio::select! { |
| 216 | result = http::run_server( | 221 | result = http::run_server( |
| 217 | config, | 222 | config, |
| @@ -219,6 +224,8 @@ async fn main() -> Result<()> { | |||
| 219 | relay_with_db.database, | 224 | relay_with_db.database, |
| 220 | metrics, | 225 | metrics, |
| 221 | purgatory, | 226 | purgatory, |
| 227 | http_write_policy, | ||
| 228 | http_rejected_index, | ||
| 222 | ) => { | 229 | ) => { |
| 223 | result? | 230 | result? |
| 224 | } | 231 | } |
| @@ -230,7 +237,7 @@ async fn main() -> Result<()> { | |||
| 230 | } | 237 | } |
| 231 | } | 238 | } |
| 232 | } | 239 | } |
| 233 | 240 | ||
| 234 | #[cfg(not(unix))] | 241 | #[cfg(not(unix))] |
| 235 | { | 242 | { |
| 236 | tokio::select! { | 243 | tokio::select! { |
| @@ -240,6 +247,8 @@ async fn main() -> Result<()> { | |||
| 240 | relay_with_db.database, | 247 | relay_with_db.database, |
| 241 | metrics, | 248 | metrics, |
| 242 | purgatory, | 249 | purgatory, |
| 250 | http_write_policy, | ||
| 251 | http_rejected_index, | ||
| 243 | ) => { | 252 | ) => { |
| 244 | result? | 253 | result? |
| 245 | } | 254 | } |