Add archive relay query augmentation and access-based GC (v0.45.0)

- Add async archive relay querying (local results immediate, archives in background)
- Add query caching with filter normalization to avoid repeated requests
- Add session-deduplicated access tracking for events
- Add continuous garbage collection based on access patterns
- Auto-detect storage limit (80% of filesystem) when ORLY_MAX_STORAGE_BYTES=0
- Support NIP-50 search queries to archive relays

New environment variables:
- ORLY_ARCHIVE_ENABLED: Enable archive relay query augmentation
- ORLY_ARCHIVE_RELAYS: Comma-separated archive relay URLs
- ORLY_ARCHIVE_TIMEOUT_SEC: Archive query timeout
- ORLY_ARCHIVE_CACHE_TTL_HRS: Query deduplication window
- ORLY_GC_ENABLED: Enable access-based garbage collection
- ORLY_MAX_STORAGE_BYTES: Max storage (0=auto 80%)
- ORLY_GC_INTERVAL_SEC: GC check interval
- ORLY_GC_BATCH_SIZE: Events per GC cycle

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
woikos
2026-01-02 19:35:16 +01:00
parent 0008d33792
commit 8a14cec3cd
19 changed files with 1718 additions and 2 deletions

View File

@@ -29,8 +29,10 @@ import (
cashuiface "next.orly.dev/pkg/interfaces/cashu"
"next.orly.dev/pkg/ratelimit"
"next.orly.dev/pkg/spider"
"next.orly.dev/pkg/storage"
dsync "next.orly.dev/pkg/sync"
"next.orly.dev/pkg/wireguard"
"next.orly.dev/pkg/archive"
"git.mleku.dev/mleku/nostr/interfaces/signer/p8k"
)
@@ -512,6 +514,40 @@ func Run(
}
}
// Initialize access tracker for storage management (only for Badger backend)
if badgerDB, ok := db.(*database.D); ok {
l.accessTracker = storage.NewAccessTracker(badgerDB, 100000) // 100k dedup cache
l.accessTracker.Start()
log.I.F("access tracker initialized")
// Initialize garbage collector if enabled
maxBytes, gcEnabled, gcIntervalSec, gcBatchSize := cfg.GetStorageConfigValues()
if gcEnabled {
gcCfg := storage.GCConfig{
MaxStorageBytes: maxBytes,
Interval: time.Duration(gcIntervalSec) * time.Second,
BatchSize: gcBatchSize,
MinAgeSec: 3600, // Minimum 1 hour before eviction
}
l.garbageCollector = storage.NewGarbageCollector(ctx, badgerDB, l.accessTracker, gcCfg)
l.garbageCollector.Start()
log.I.F("garbage collector started (interval: %ds, batch: %d)", gcIntervalSec, gcBatchSize)
}
}
// Initialize archive relay manager if enabled
archiveEnabled, archiveRelays, archiveTimeoutSec, archiveCacheTTLHrs := cfg.GetArchiveConfigValues()
if archiveEnabled && len(archiveRelays) > 0 {
archiveCfg := archive.Config{
Enabled: true,
Relays: archiveRelays,
TimeoutSec: archiveTimeoutSec,
CacheTTLHrs: archiveCacheTTLHrs,
}
l.archiveManager = archive.New(ctx, db, archiveCfg)
log.I.F("archive relay manager initialized with %d relays", len(archiveRelays))
}
// Start rate limiter if enabled
if limiter != nil && limiter.IsEnabled() {
limiter.Start()
@@ -621,6 +657,24 @@ func Run(
log.I.F("rate limiter stopped")
}
// Stop archive manager if running
if l.archiveManager != nil {
l.archiveManager.Stop()
log.I.F("archive manager stopped")
}
// Stop garbage collector if running
if l.garbageCollector != nil {
l.garbageCollector.Stop()
log.I.F("garbage collector stopped")
}
// Stop access tracker if running
if l.accessTracker != nil {
l.accessTracker.Stop()
log.I.F("access tracker stopped")
}
// Stop bunker server if running
if l.bunkerServer != nil {
l.bunkerServer.Stop()