mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 23:18:24 +00:00
feat(config): make holding cleanup timings configurable
This commit is contained in:
+18
-1
@@ -169,6 +169,23 @@
|
||||
# Default: 12
|
||||
# NGIT_NAUGHTY_LIST_EXPIRATION_HOURS=12
|
||||
|
||||
# ============================================================================
|
||||
# HOLDING DB CLEANUP
|
||||
# ============================================================================
|
||||
|
||||
# Retention window in seconds for deleted events kept in holding DB
|
||||
# Used by startup catch-up and periodic expiration cleanup
|
||||
# Must be greater than 0
|
||||
# CLI: --holding-retention-secs <seconds>
|
||||
# Default: 7776000 (90 days)
|
||||
# NGIT_HOLDING_RETENTION_SECS=7776000
|
||||
|
||||
# Interval in seconds between holding DB background cleanup passes
|
||||
# Must be greater than 0
|
||||
# CLI: --holding-cleanup-interval-secs <seconds>
|
||||
# Default: 86400 (24 hours)
|
||||
# NGIT_HOLDING_CLEANUP_INTERVAL_SECS=86400
|
||||
|
||||
# ============================================================================
|
||||
# GRASP-05 ARCHIVE MODE
|
||||
# ============================================================================
|
||||
@@ -345,4 +362,4 @@
|
||||
# When unset (default), connections are unlimited (defers to OS fd limits and infrastructure controls)
|
||||
# CLI: --max-connections <count>
|
||||
# Default: unlimited
|
||||
# NGIT_MAX_CONNECTIONS=4096
|
||||
# NGIT_MAX_CONNECTIONS=4096
|
||||
|
||||
@@ -492,6 +492,58 @@ NGIT_REJECTED_COLD_INDEX_EXPIRY_SECS=1209600
|
||||
|
||||
---
|
||||
|
||||
### Holding DB Cleanup Configuration
|
||||
|
||||
These options control retention and cleanup cadence for deleted events archived in the holding database.
|
||||
|
||||
#### `NGIT_HOLDING_RETENTION_SECS`
|
||||
|
||||
**Description:** How long deleted events are retained in the holding DB before expiration cleanup removes them
|
||||
**Type:** Integer (seconds)
|
||||
**Default:** `7776000` (90 days)
|
||||
**Required:** No
|
||||
|
||||
**Examples:**
|
||||
|
||||
```bash
|
||||
# Default: 90 days
|
||||
NGIT_HOLDING_RETENTION_SECS=7776000
|
||||
|
||||
# Short retention (30 days)
|
||||
NGIT_HOLDING_RETENTION_SECS=2592000
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
|
||||
- Must be greater than 0
|
||||
- Used by both startup catch-up cleanup and periodic cleanup passes
|
||||
|
||||
---
|
||||
|
||||
#### `NGIT_HOLDING_CLEANUP_INTERVAL_SECS`
|
||||
|
||||
**Description:** Interval between periodic holding DB expiration cleanup passes
|
||||
**Type:** Integer (seconds)
|
||||
**Default:** `86400` (24 hours)
|
||||
**Required:** No
|
||||
|
||||
**Examples:**
|
||||
|
||||
```bash
|
||||
# Default: daily cleanup
|
||||
NGIT_HOLDING_CLEANUP_INTERVAL_SECS=86400
|
||||
|
||||
# Every 6 hours
|
||||
NGIT_HOLDING_CLEANUP_INTERVAL_SECS=21600
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
|
||||
- Must be greater than 0
|
||||
- Smaller values clean up expired records sooner at the cost of more background work
|
||||
|
||||
---
|
||||
|
||||
### GRASP-05 Archive Configuration
|
||||
|
||||
These options enable archive/mirror/backup mode per the GRASP-05 specification.
|
||||
|
||||
@@ -178,6 +178,20 @@ let
|
||||
description = "Hours before removing relay from naughty list";
|
||||
};
|
||||
|
||||
holdingRetentionSecs = mkOption {
|
||||
type = types.int;
|
||||
default = 7776000;
|
||||
description =
|
||||
"Retention window in seconds for deleted events in holding DB (default: 90 days)";
|
||||
};
|
||||
|
||||
holdingCleanupIntervalSecs = mkOption {
|
||||
type = types.int;
|
||||
default = 86400;
|
||||
description =
|
||||
"Interval in seconds between holding DB cleanup passes (default: 24 hours)";
|
||||
};
|
||||
|
||||
archiveAll = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -369,6 +383,9 @@ let
|
||||
toString cfg.rejectedColdIndexExpirySecs;
|
||||
NGIT_NAUGHTY_LIST_EXPIRATION_HOURS =
|
||||
toString cfg.naughtyListExpirationHours;
|
||||
NGIT_HOLDING_RETENTION_SECS = toString cfg.holdingRetentionSecs;
|
||||
NGIT_HOLDING_CLEANUP_INTERVAL_SECS =
|
||||
toString cfg.holdingCleanupIntervalSecs;
|
||||
NGIT_ARCHIVE_ALL = if cfg.archiveAll then "true" else "false";
|
||||
NGIT_ARCHIVE_WHITELIST = concatStringsSep "," cfg.archiveWhitelist;
|
||||
NGIT_ARCHIVE_GRASP_SERVICES =
|
||||
|
||||
@@ -4,6 +4,7 @@ use nostr_sdk::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Whitelist entry for repository/archive filtering
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
@@ -428,6 +429,22 @@ pub struct Config {
|
||||
#[arg(long, env = "NGIT_NAUGHTY_LIST_EXPIRATION_HOURS", default_value_t = 12)]
|
||||
pub naughty_list_expiration_hours: u64,
|
||||
|
||||
/// Retention window in seconds for deleted events kept in holding DB.
|
||||
#[arg(
|
||||
long,
|
||||
env = "NGIT_HOLDING_RETENTION_SECS",
|
||||
default_value_t = crate::nostr::holding::DEFAULT_RETENTION.as_secs()
|
||||
)]
|
||||
pub holding_retention_secs: u64,
|
||||
|
||||
/// Interval in seconds between background holding cleanup passes.
|
||||
#[arg(
|
||||
long,
|
||||
env = "NGIT_HOLDING_CLEANUP_INTERVAL_SECS",
|
||||
default_value_t = crate::nostr::holding::DEFAULT_CLEANUP_INTERVAL.as_secs()
|
||||
)]
|
||||
pub holding_cleanup_interval_secs: u64,
|
||||
|
||||
/// Enable GRASP-05 archive mode: accept all announcements regardless of listing (WARNING: storage risk)
|
||||
#[arg(long, env = "NGIT_ARCHIVE_ALL", default_value_t = false)]
|
||||
pub archive_all: bool,
|
||||
@@ -661,6 +678,18 @@ impl Config {
|
||||
// Validate repository whitelist configuration
|
||||
let repository_whitelist = WhitelistEntry::parse_whitelist(&self.repository_whitelist);
|
||||
|
||||
if self.holding_retention_secs == 0 {
|
||||
return Err(anyhow!(
|
||||
"NGIT_HOLDING_RETENTION_SECS must be greater than 0"
|
||||
));
|
||||
}
|
||||
|
||||
if self.holding_cleanup_interval_secs == 0 {
|
||||
return Err(anyhow!(
|
||||
"NGIT_HOLDING_CLEANUP_INTERVAL_SECS must be greater than 0"
|
||||
));
|
||||
}
|
||||
|
||||
// Fatal error: repository_whitelist with archive_read_only=true (incompatible)
|
||||
if !repository_whitelist.is_empty() {
|
||||
let read_only = self.archive_read_only.unwrap_or(archive_enabled);
|
||||
@@ -751,6 +780,16 @@ impl Config {
|
||||
EventBlacklistConfig { blacklisted_npubs }
|
||||
}
|
||||
|
||||
/// Holding DB retention as a duration.
|
||||
pub fn holding_retention(&self) -> Duration {
|
||||
Duration::from_secs(self.holding_retention_secs)
|
||||
}
|
||||
|
||||
/// Holding DB periodic cleanup interval as a duration.
|
||||
pub fn holding_cleanup_interval(&self) -> Duration {
|
||||
Duration::from_secs(self.holding_cleanup_interval_secs)
|
||||
}
|
||||
|
||||
/// Create config for testing
|
||||
#[cfg(test)]
|
||||
pub fn for_testing() -> Self {
|
||||
@@ -781,6 +820,9 @@ impl Config {
|
||||
rejected_hot_cache_duration_secs: 120,
|
||||
rejected_cold_index_expiry_secs: 604800,
|
||||
naughty_list_expiration_hours: 12,
|
||||
holding_retention_secs: crate::nostr::holding::DEFAULT_RETENTION.as_secs(),
|
||||
holding_cleanup_interval_secs: crate::nostr::holding::DEFAULT_CLEANUP_INTERVAL
|
||||
.as_secs(),
|
||||
archive_all: false,
|
||||
archive_whitelist: String::new(),
|
||||
archive_grasp_services: String::new(),
|
||||
|
||||
+6
-11
@@ -399,11 +399,10 @@ async fn run_relay(config: Config) -> Result<()> {
|
||||
// 1) startup catch-up pass (runs once)
|
||||
// 2) periodic background cleanup pass
|
||||
let holding_cleanup_store = relay_with_db.holding.clone();
|
||||
let holding_retention = config.holding_retention();
|
||||
let holding_cleanup_interval = config.holding_cleanup_interval();
|
||||
match holding_cleanup_store
|
||||
.cleanup_expired(
|
||||
nostr_sdk::prelude::Timestamp::now(),
|
||||
nostr::holding::DEFAULT_RETENTION,
|
||||
)
|
||||
.cleanup_expired(nostr_sdk::prelude::Timestamp::now(), holding_retention)
|
||||
.await
|
||||
{
|
||||
Ok(stats) => {
|
||||
@@ -423,7 +422,6 @@ async fn run_relay(config: Config) -> Result<()> {
|
||||
}
|
||||
|
||||
let (holding_cleanup_shutdown_tx, mut holding_cleanup_shutdown_rx) = watch::channel(false);
|
||||
let holding_cleanup_interval = nostr::holding::DEFAULT_CLEANUP_INTERVAL;
|
||||
let holding_cleanup_task = tokio::spawn(async move {
|
||||
let mut interval = tokio::time::interval_at(
|
||||
tokio::time::Instant::now() + holding_cleanup_interval,
|
||||
@@ -434,10 +432,7 @@ async fn run_relay(config: Config) -> Result<()> {
|
||||
tokio::select! {
|
||||
_ = interval.tick() => {
|
||||
match holding_cleanup_store
|
||||
.cleanup_expired(
|
||||
nostr_sdk::prelude::Timestamp::now(),
|
||||
nostr::holding::DEFAULT_RETENTION,
|
||||
)
|
||||
.cleanup_expired(nostr_sdk::prelude::Timestamp::now(), holding_retention)
|
||||
.await
|
||||
{
|
||||
Ok(stats) => {
|
||||
@@ -466,8 +461,8 @@ async fn run_relay(config: Config) -> Result<()> {
|
||||
}
|
||||
});
|
||||
info!(
|
||||
retention_secs = nostr::holding::DEFAULT_RETENTION.as_secs(),
|
||||
interval_secs = nostr::holding::DEFAULT_CLEANUP_INTERVAL.as_secs(),
|
||||
retention_secs = holding_retention.as_secs(),
|
||||
interval_secs = holding_cleanup_interval.as_secs(),
|
||||
"Holding cleanup task started"
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user