Reaper Cancel at 5mins #6
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
You are fixing a bug in Paperclip where long-running adapter runs are reaped
after exactly 5 minutes, even though the adapter is actively producing
output. The repo is at /Users/Repositories/revitalize. Work on a new branch
off
dev— do NOT commit directly todev.=== THE BUG ===
External adapters that declare
hasOutOfProcessLiveness: true(e.g.paperclip-adapter-claude-k8s) don't call
onSpawnduring their run. Thereaper at
server/src/services/heartbeat.ts:3876-3942decides livenessfor these adapters by comparing
heartbeatRuns.updatedAtagainst a5-minute staleness threshold.
Only
persistRunProcessMetadata()(line 2802) refreshesupdatedAt, andit is only called from the
onSpawnhandler (line 5676). TheonLoghandler (line 5545) writes to the log store and publishes SSE events but
DOES NOT touch
updatedAt.Result: for out-of-process adapters that don't call
onSpawn,updatedAtis frozen at run start, and the reaper guaranteed-fires atexactly 5 minutes regardless of actual activity. Any run longer than
5 minutes fails with
adapter_liveness_lost.=== THE FIX ===
Treat log output as proof of life for
hasOutOfProcessLivenessadapters.When the adapter calls
onLog, refreshheartbeatRuns.updatedAtso thereaper's staleness window resets.
Apply this change in
server/src/services/heartbeat.ts.Find the
onLoghandler definition around line 5545 (search forconst onLog = async (stream: "stdout" | "stderr", chunk: string)).Inside that handler, AFTER
publishLiveEvent(...)(around line 5577),add a DB update that sets
updatedAt: new Date()on the current run row,but ONLY for adapters with out-of-process liveness AND only when the
last refresh was more than REFRESH_THROTTLE_MS ago.
=== THROTTLING (IMPORTANT) ===
Adapter runs produce ~1 log chunk/second. Without throttling, every run
would write to
heartbeatRunsonce per second — a hot row contentionpoint and significant WAL churn.
Throttle to once every 60 seconds per run. Reaper window is 5 minutes, so
a 60-second refresh cadence gives 5× margin. Implementation:
Inside
onLog, afterpublishLiveEvent:Also: when a run ends, clean up the map entry to prevent unbounded
growth. Find where
activeRunExecutions.delete(run.id)is called (aroundline 6061) and add
lastUpdatedAtRefresh.delete(run.id)immediatelyafter it.
=== IMPORTS / SYMBOLS TO VERIFY ===
Before editing, check:
db,heartbeatRuns,eqare already imported/in scope. They are —used on lines 2808, 2815, and elsewhere. Do not re-import.
adapterHasOutOfProcessLivenessis already defined in this file.Don't re-define.
runandagentare in the closure whereonLogis defined. Confirmby reading lines 5500-5545 before the handler.
=== DO NOT ===
needs finer granularity, you are misreading the reaper — its threshold
is 300 seconds.
throttle. A fixed interval is correct.
is broken.
persistRunProcessMetadata— it still handlesonSpawncorrectly for in-process adapters.
onLogbeyond adding this block..catch(() => {}). Ifthe update fails, it should surface.
=== TESTING ===
Run the existing test suite using the repo's standard test command
(check
package.jsonscripts — likelypnpm testorpnpm --filter @paperclipai/server test). All existing tests muststill pass.
Find the test file covering
reapOrphanedRunsor the heartbeatservice. Look in
server/src/__tests__/orserver/src/services/__tests__/. Add ONE new test that verifies:given a
hasOutOfProcessLivenessadapter, callingonLogcausesupdatedAtto advance in the DB (within throttle window). If thetest harness already has a mock out-of-process adapter, reuse it.
If adding a test would require >30 lines of scaffolding, skip it
and note in the PR description why.
Do NOT run the adapter end-to-end — no k8s access needed.
=== BRANCH, COMMIT, PUSH, PR ===
Create a new branch off
dev:git checkout dev && git pull && git checkout -b fix/heartbeat-updatedat-refresh-on-log
Make the changes and commit. Commit message:
Push the branch:
git push -u origin fix/heartbeat-updatedat-refresh-on-log
Open a PR against
devusinggh pr create. Title:PR body — use a heredoc with this structure:
=== WRAPPING UP ===
Report back with:
If anything in the instructions doesn't match what you find in the code
(wrong line numbers, renamed symbols, missing helpers), STOP and report
what you found. Do not improvise.