fix(debug): sweep expired paste.rs uploads on a real timer (#16431)

Previously 'hermes debug share' uploads only got DELETEd when the user
ran 'hermes debug share' again — opportunistic-sweep-on-invoke was the
only cleanup path. A user who uploaded once and never ran debug again
left pastes up until paste.rs's retention kicked in (which, empirically,
never actually expires them).

Hook _sweep_expired_pastes into the gateway cron ticker at the same
hourly cadence as the image/document cache cleanups. The opportunistic
sweep in 'hermes debug share' stays as a fallback for CLI-only users
who never start the gateway.
This commit is contained in:
Teknium
2026-04-27 00:36:33 -07:00
committed by GitHub
parent 2e6699b319
commit 90a3e73daf
2 changed files with 26 additions and 6 deletions

View File

@@ -11153,13 +11153,16 @@ def _start_cron_ticker(stop_event: threading.Event, adapters=None, loop=None, in
cron delivery path so live adapters can be used for E2EE rooms. cron delivery path so live adapters can be used for E2EE rooms.
Also refreshes the channel directory every 5 minutes and prunes the Also refreshes the channel directory every 5 minutes and prunes the
image/audio/document cache once per hour. image/audio/document cache + expired ``hermes debug share`` pastes
once per hour.
""" """
from cron.scheduler import tick as cron_tick from cron.scheduler import tick as cron_tick
from gateway.platforms.base import cleanup_image_cache, cleanup_document_cache from gateway.platforms.base import cleanup_image_cache, cleanup_document_cache
from hermes_cli.debug import _sweep_expired_pastes
IMAGE_CACHE_EVERY = 60 # ticks — once per hour at default 60s interval IMAGE_CACHE_EVERY = 60 # ticks — once per hour at default 60s interval
CHANNEL_DIR_EVERY = 5 # ticks — every 5 minutes CHANNEL_DIR_EVERY = 5 # ticks — every 5 minutes
PASTE_SWEEP_EVERY = 60 # ticks — once per hour
logger.info("Cron ticker started (interval=%ds)", interval) logger.info("Cron ticker started (interval=%ds)", interval)
tick_count = 0 tick_count = 0
@@ -11200,6 +11203,17 @@ def _start_cron_ticker(stop_event: threading.Event, adapters=None, loop=None, in
except Exception as e: except Exception as e:
logger.debug("Document cache cleanup error: %s", e) logger.debug("Document cache cleanup error: %s", e)
if tick_count % PASTE_SWEEP_EVERY == 0:
try:
deleted, remaining = _sweep_expired_pastes()
if deleted:
logger.info(
"Paste sweep: deleted %d expired paste(s), %d pending",
deleted, remaining,
)
except Exception as e:
logger.debug("Paste sweep error: %s", e)
stop_event.wait(timeout=interval) stop_event.wait(timeout=interval)
logger.info("Cron ticker stopped") logger.info("Cron ticker stopped")

View File

@@ -45,8 +45,13 @@ def _pending_file() -> Path:
Each entry: ``{"url": "...", "expire_at": <unix_ts>}``. Scheduled Each entry: ``{"url": "...", "expire_at": <unix_ts>}``. Scheduled
DELETEs used to be handled by spawning a detached Python process per DELETEs used to be handled by spawning a detached Python process per
paste that slept for 6 hours; those accumulated forever if the user paste that slept for 6 hours; those accumulated forever if the user
ran ``hermes debug share`` repeatedly. We now persist the schedule ran ``hermes debug share`` repeatedly.
to disk and sweep expired entries on the next debug invocation.
Deletion is now driven by the gateway's cron ticker
(``gateway/run.py::_start_cron_ticker``) which calls
``_sweep_expired_pastes`` once per hour. ``hermes debug share`` also
runs an opportunistic sweep on entry as a fallback for CLI-only users
who never start the gateway.
""" """
return get_hermes_home() / "pastes" / "pending.json" return get_hermes_home() / "pastes" / "pending.json"
@@ -223,9 +228,10 @@ def _schedule_auto_delete(urls: list[str], delay_seconds: int = _AUTO_DELETE_SEC
interpreters that never exited until the sleep completed. interpreters that never exited until the sleep completed.
The replacement is stateless: we append to ``~/.hermes/pastes/pending.json`` The replacement is stateless: we append to ``~/.hermes/pastes/pending.json``
and rely on opportunistic sweeps (``_sweep_expired_pastes``) called from and the gateway's cron ticker sweeps expired entries once per hour.
every ``hermes debug`` invocation. If the user never runs ``hermes debug`` ``hermes debug share`` also runs an opportunistic sweep as a fallback
again, paste.rs's own retention policy handles cleanup. for CLI-only users. If neither runs again, paste.rs's own retention
policy handles cleanup.
""" """
_record_pending(urls, delay_seconds=delay_seconds) _record_pending(urls, delay_seconds=delay_seconds)