Fix reconcile lock expiry during aggregation - #536
Merged
Conversation
…k-fencing # Conflicts: # src/Workflows/class-wp-agent-workflow-scoped-drain.php # src/Workflows/register-workflow-branch-executor.php # stubs/action-scheduler-classes.php # tests/workflow-as-branch-smoke.php # tests/workflow-request-controller-smoke.php # tests/workflow-scoped-drain-smoke.php
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
Root cause
Reconciliation held a fixed 60-second option lock while executing arbitrary aggregate workflow steps. Agent and ability-backed aggregation can legitimately exceed that lease, allowing another reconciler to reclaim the lock while the original process continued.
Durable continuation
For Action Scheduler-owned runs, the all-terminal reconcile transition enqueues one unique
wp_agent_workflow_run_aggregateaction and persists its generation-bound owner.queued: the durable aggregate action exists; duplicate reconcile delivery is a no-oprunning: the claimed action crossed the durable effect-start boundary; no duplicate action may rerun aggregationcommitted: aggregate output or an honest uncertain-outcome failure is durable; only resume remainsThe action transitions
queuedtorunningunder the short reconcile lock, aggregates outside the lock, then reacquires the lock and commits only if its owner token and suspension generation still match.Failure lifecycle
The canonical Action Scheduler failure registrations preserve main's branch/reconcile receipt recovery and additionally route aggregate actions by hook:
queuedaggregate: safely re-enqueue because effects did not beginrunningaggregate: persistworkflow_parallel_aggregation_outcome_uncertain; never rerun effectscommitted: enqueue/resume from durable outputThere is no aggregate claim timeout and no reconcile hot retry while healthy aggregation is active.
Main integration
Merged
origin/mainat1d1b9f06with a normal merge commit (e914e65), preserving PRs #535 and #534:The scoped drain/cleanup hooks are now ordered as branch, reconcile, aggregate, and resume. Concurrency headroom is additive and bounded for all four; batch size is pinned to one while branch or aggregate effects are active.
Verification
Focused combined matrix:
php tests/workflow-as-branch-smoke.php(136 assertions)php tests/workflow-branch-concurrency-gate-smoke.php(44 assertions)php tests/workflow-async-branch-payload-smoke.php(40 assertions)php tests/workflow-scoped-drain-smoke.phpphp tests/workflow-request-controller-smoke.phpphp tests/workflow-reconcile-race-smoke.phpphp tests/workflow-reconcile-branch-authorization-smoke.phpphp tests/workflow-parallel-async-smoke.phpProject gates:
composer testcomposer phpstangit diff --checkgit diff --cached --checkCoverage includes partial admission, branch reconcile contention, failed branch/reconcile recovery, healthy long aggregation, aggregate crash lifecycle, committed-before-resume recovery, duplicate delivery, custom stores, legacy/tokenless payloads, bounded four-hook headroom, and terminal completion/cleanup single-winner behavior.
AI assistance
Implemented and tested with AI assistance. The final integration was reviewed against current main, Action Scheduler claim/failure semantics, pluggable store ownership, and the complete project test/static-analysis gates.