feat(persistence): event-driven snapshot checkpointing with policy safety net (#2005) - #2008
arnabnandy7 wants to merge 1 commit into
Conversation
…fety net (embabel#2005) Signed-off-by: Arnab Nandy <arnab_nandy7@yahoo.com>
|
From Claude: The InterruptedException path is the one to verify. _status.set(TERMINATED) is a direct atomic write, not
This needs a targeted test: process in RUNNING, action throws InterruptedException, verify status is How the two layers interact — and what happens when an event is missing The composite listener wiring is correct: agentProcessCheckpointListener returns AgenticEventListener, The safety net (doSave/doUpdate) fires when the framework writes to the repository. But there is no
So the safety net is not actually a safety net for termination paths; it only catches events missed during Issues to raise:
PR requires very careful development — as it represents a core platform component — and e2e testing, thanks |
|
Compiling more.... Intent:
The safety net genuinely covers the missing-event case for ALL states, not just non-terminal ones. But the deduplication implementation is broken for the normal sequential case. When both layers fire in sequence (which is the common case, not a race):
The CAS exception never fires because versions differ (1 vs 2). So two identical snapshots are written every The fix: before serializing, compare whether the snapshot's stored version already reflects the current The design is right. The deduplication implementation needs to match the design. Two concepts, both lightweight:
checkpoint() becomes: if lastPersistedVersion[processId] >= process.stateVersion → skip (already done) That's it. No pre-write store read needed to detect duplicates. No CAS exception dance. Works identically for How the two layers interact:
The fallback genuinely does real work only when the event was absent. Where lastPersistedVersion lives: @arnabnandy7 - please confirm understanding before proceeding, thanks |
|
@igordayen Confirming my understanding of both your review here and your latest direction on #2005. The current CAS check does not deduplicate the normal sequential event -> doUpdate() flow: the second checkpoint reads the newly stored version and successfully writes another version of the same state. It also cannot safely treat every concurrent version conflict as an identical-state duplicate. I understand the state-version approach you suggested to address that, but your latest issue comment supersedes that approach by removing the need for two checkpointing layers. I'll follow the revised scope in a separate PR linked to #1988:
Once that replacement PR is available, I'll link it here and close this PR as superseded. I've also acknowledged the revised scope on #2005: #2005 (comment) |
|
Closing this PR as superceded to #2010 |
@arnabnandy7 termination/kill APIs: process A can terminate process B. Please refer to the user guide. Thanks |
Summary
Transitions process snapshot checkpointing from an invocation-only model (
save()/update()) to an event-driven primary architecture, backed by repository policy checks as a safety net and CAS deduplication.Problem & Motivation
Previously, durable snapshots were only saved synchronously during
PersistentAgentProcessRepository.save()andupdate(). This meant process state transitions triggered asynchronously or within agent turn execution (such as entering wait states, completing, or terminating) were not checkpointed until or unless an explicit repository write occurred.What's Changed
PersistentAgentProcessRepositorynow implementsAgenticEventListener, reactively checkpointing snapshots on key lifecycle events (AgentProcessWaitingEvent,AgentProcessCompletedEvent,AgentProcessFailedEvent,ProcessKilledEvent, andAgentProcessTerminatedEvent).AgentProcessTerminatedEvent: emitted whenever a process transitions toTERMINATED(via early termination signals, policies, turn termination, or explicit termination).AgentProcessRestoredEvent: emitted after snapshot reconstitution inPersistentAgentProcessRepository.restore().checkpointIfNeeded()insave()andupdate()to ensure processes are persisted even if lifecycle events are bypassed or deferred.current.version >= nextVersion).agentProcessCheckpointListenerbean inAgentPlatformConfiguration, exposed SPI accessorAgentProcessPersistence.checkpointListener(), and updated reference documentation and architecture guides.Verification
Closes #2005