fix(automerge): requeue transiently-failed evaluations instead of dropping them - #38970
fix(automerge): requeue transiently-failed evaluations instead of dropping them#38970willemkokke wants to merge 2 commits into
Conversation
… them The pr_auto_merge queue handler always returned nil, telling the queue every item was handled even when handlePullRequestAutoMerge bailed out on a transient failure (database read, git repository access). The queue's retry mechanism (workergroup re-pushes unhandled items) was never engaged, so one hiccup at the wrong moment permanently lost a scheduled merge: the pull request stayed green with auto-merge armed and never merged, with no trace on the PR page. handlePullRequestAutoMerge now returns an error for transient infrastructure failures and nil for everything genuinely handled, including definite refusals retrying cannot cure (pull request deleted, head branch gone, checks not passing, CheckPullMergeable sentinel refusals). The handler requeues transiently-failed items, bounded per item so a persistently failing item cannot spin in the queue forever, since the queue has no retry limit or dead-letter of its own. Also log the precise CheckPullMergeable refusal reason instead of the misleading "scheduled to automerge by an unauthorized user": the error already carries which condition failed (status checks, approvals, requested changes, official review requests, behind base branch, protected files). Fixes go-gitea#38969 Signed-off-by: Willem Kokke <willem@humain-studios.com>
bircni
left a comment
There was a problem hiding this comment.
sorry but this looks like completely AI generated (which is fine)
But please follow the guidelines and state so https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md#ai-contribution-policy
Also we have a guideline for https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md#pr-title-and-summary
TestHandlerRequeuesOnRepositoryAccessFailure exercises the full evaluation with nothing mocked but the repository storage location: a scheduled auto merge whose git repository is momentarily inaccessible must be reported back to the queue for requeueing. Apart from the clearTransientFailures cleanup line, the test compiles against the previous handler too, and fails there: the old handler reported the item as handled and returned nil, permanently losing the scheduled merge. Signed-off-by: Willem Kokke <willem@humain-studios.com>
|
My apologies, I messed up. I'll fix it. |
|
The retry count should be saved in the automerge's database record? |
|
Hi @wxiaoguang I did consider this, and I intentionally decided against it for this pr. I fixed this to patch an active production issue (this has been running in production for over a week running the same workloads it ran before but without the occasional auto merge never being triggered) I wanted to avoid a migration and just have a drop-in binary. (data was safely backed up regardless) There are benefits to it for sure, the retries would survive restarts, you could inspect it on a running system, and it might be a good time to do #30691 (adding a field to display a merge error message on the page). It was also not super clear what the semantics should be. If the retry count is on that row, it is shared between all (PR, sha) pairs. Do we reset when the sha moves? Keeping the count in memory also allows it to be trivially back-ported if that is a thing your organisation does, or anyone else needs. This PR is just a bug fix, the follow-up(#38972) is auto merge hardening, a reconciler that re-queues merges after a restart and when lost due to other failures. That would reduce the need to persist the data, as there is no risk of permanently losing an auto merge anymore. |
Update: OK, I see the reason, "database restart" |
|
I think the design can be simplified like this (with #38972)
|
Fixes #38969
The
pr_auto_mergequeue handler always returnednil, telling the queue every item was handled even whenhandlePullRequestAutoMergebailed out on a transient failure (a database read, a git repository open). The queue's retry mechanism —workergroup.gore-pushes items the handler returns as unhandled — was never engaged, so one hiccup at the wrong moment permanently lost a scheduled merge: the pull request stayed green with auto-merge armed and never merged, with nothing on the PR page and only a single generic server log line. On a PR whose CI has already settled, no further event ever re-enqueues the evaluation. Issue #38969 has the full analysis with line-by-line citations.What this changes
handlePullRequestAutoMergenow returns an error for transient infrastructure failures (DB reads, git repository access) andnilfor everything genuinely handled — merged, or refused for a reason retrying cannot cure (pull request deleted, head branch gone, SHA superseded, checks not passing,CheckPullMergeablesentinel refusals such asErrHasMerged/ErrIsClosed/ErrNotReadyToMerge).handlerreturns transiently-failed items to the queue so its existing retry path engages, bounded per item (maxTransientRetries, in-memory): the queue's requeue loop has no retry limit and no dead-letter, so unbounded requeueing would trade a silent drop for a permanent spin — we have watched a poison item in another queue do exactly that for days. When the bound is reached the item is dropped with a loudlog.Error; thepull_auto_mergerow stays in place, so the next event for the PR re-evaluates it.ErrNotReadyToMergebranch now logs the precise refusal reason the error already carries (status checks / approvals / requested changes / official review requests / behind base branch / code owner reviews / protected files) instead of the misleading... was scheduled to automerge by an unauthorized user, which sends anyone debugging from logs chasing a permissions problem that may not exist.handlePullRequestAutoMergebecomes a function variable (same pattern asautomergequeue.AddToQueueandpull.AddPullRequestToCheckQueue) so the handler's requeue contract is unit-testable.pull_service.Mergefailures deliberately stay terminal (unchanged behaviour, existing FIXME kept): retrying a failed merge is riskier than retrying a read, and surfacing merge errors on the PR page is tracked separately (#30691).Testing
go test ./services/automerge/... ./modules/queue/...TestHandlerRequeuesOnRepositoryAccessFailureexercises the full evaluation with nothing mocked but the repository storage location — a fixture PR with a scheduled auto merge whose git repository is inaccessible. Run against the unpatched handler atmain(83af7aa) it fails (handlerreturnsnil, the scheduled merge is dropped); with this PR it passes (the item is returned for requeue). Everything except the oneclearTransientFailurescleanup line compiles against the old code as-is.go vet,gofmtclean.A complementary, heavier hardening — a periodic reconciler over
pull_auto_mergerows that re-enqueues any still-open scheduled merge, which would also self-heal losses from restarts and missed events — is sketched in #38969 and intentionally not part of this PR.AI assistance
AI assistance (Claude) was used to prepare this patch, its tests, and this description, per the AI Contribution Policy. The analysis and the change have been reviewed and tested by me, I understand and can defend every part of it, and I will answer review questions myself.