fix(kernel): preserve cron jobs across hand reactivation#1019
Open
letzdoo-js wants to merge 1 commit intoRightNow-AI:mainfrom
Open
fix(kernel): preserve cron jobs across hand reactivation#1019letzdoo-js wants to merge 1 commit intoRightNow-AI:mainfrom
letzdoo-js wants to merge 1 commit intoRightNow-AI:mainfrom
Conversation
Bug: in activate_hand(), kill_agent() is called on the existing agent BEFORE the new agent is spawned. kill_agent() invokes cron_scheduler.remove_agent_jobs() which deletes all cron jobs from memory AND persists [] to cron_jobs.json. The reassign_agent_jobs() call further down was meant to migrate jobs from old to new (per RightNow-AI#461), but it always runs as a no-op because the jobs are already gone — the order of operations defeats the fix. Symptom: every daemon restart silently destroys cron jobs for hand-style agents. cron_jobs.json is rewritten as []. /api/cron/jobs returns empty. No error message. Fix: snapshot the cron jobs into a local Vec BEFORE kill_agent (same pattern as saved_triggers above), then re-add them under the new agent_id AFTER spawn_agent_with_parent. Runtime state (next_run, last_run) is reset so jobs get a fresh start. The existing reassign_agent_jobs() block is kept as a defensive safety net but is now redundant in the common path. Verified with cargo check -p openfang-kernel --lib (clean compile, no warnings). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cron jobs are silently destroyed across daemon restarts for hand-style agents. Root cause: in
activate_hand(),kill_agent(old.id)runs before the new agent is spawned.kill_agentcalls
cron_scheduler.remove_agent_jobs()which deletes the agent's jobs from memory and persists[]tocron_jobs.jsonon disk. Thereassign_agent_jobs()call further down (added by#461 to fix exactly this class of bug) is therefore always a no-op — by the time it runs, the jobs are already gone.
Symptom: every daemon restart wipes
cron_jobs.jsonfor hand-managed agents./api/cron/jobsreturns empty. No error logged. Users report "my crons disappeared" with no explanation.This PR fixes it by snapshotting the cron jobs into a local
Vec<CronJob>beforekill_agent, then re-adding them under the new agent ID afterspawn_agent_with_parent— the exactsame pattern already used for
saved_triggersimmediately above (which fixed the analogous bug for triggers in #519).Fixes the "cron jobs lost on restart" regression that #461's original fix attempted but did not actually resolve due to the operation ordering.
Changes
crates/openfang-kernel/src/kernel.rs— inactivate_hand():saved_crons: Vec<CronJob>fromcron_scheduler.list_jobs(old_id)beforekill_agent(mirrors the existingsaved_triggerssnapshot 3 lines above)spawn_agent_with_parent, re-add each saved cron under the newagent_id, resettingnext_runandlast_runso jobs get a fresh schedulereassign_agent_jobs()block kept as a defensive safety net (it's now redundant in the common path but harmless)Testing
cargo check -p openfang-kernel --libpasses clean againstupstream/main(v0.5.7) — no warnings beyond the pre-existingimap-protofuture-incompat notecargo clippy --workspace --all-targets -- -D warningspasses — could not run locally (workspace requiresgdk-3.0system lib for an unrelated GUI crate); kernel crate alone isclean. CI will exercise the full workspace.
cargo test --workspacepasses — same gdk-3.0 limitation; kernel-level unit tests forcron_scheduler.list_jobsandadd_jobalready exist and the patch only uses public APIs thathave those tests.
POST /api/cron/jobsto create 3 jobs against it/api/cron/jobslists them andcron_jobs.jsoncontains themdocker restartthe daemon/api/cron/jobsreturns empty,cron_jobs.jsonis[]Security
unsafecodeCronJobinstances loaded from the trustedCronScheduler;add_job()re-runs its existing validation(max-jobs limit, per-agent count, schedule validity) on every restored job