AutoMerge silently fails when merge status is checking during process
### Summary `AutoMerge::MergeWhenChecksPassService#process` calls `merge_request.mergeable?` synchronously. If the merge status is "checking" at that moment, `mergeable?` returns `false` and the method exits silently -- no log, no retry, no reschedule. The MR stays open forever with auto-merge enabled but never merged. Opening the MR in the UI triggers a mergeability recheck, after which auto-merge succeeds immediately. ### Steps to reproduce 1. Set up a CI pipeline that creates multiple MRs in a batch using `git push -o merge_request.merge_when_pipeline_succeeds` 2. Wait for all MR pipelines to succeed 3. `AutoMergeProcessWorker` fires for each MR 4. Some MRs have merge status "checking" when the worker processes them (race condition) 5. `mergeable?` returns `false` for those MRs -- the method exits silently 6. Affected MRs stay open with auto-merge enabled but never merge The more MRs created in a short time window, the higher the chance of hitting this race condition. ### Example Project Not applicable -- requires a self-hosted GitLab instance with multiple concurrent MRs triggering auto-merge simultaneously. The bug is a race condition in server-side code. ### What is the current *bug* behavior? When `mergeable?` returns `false` because merge status is "checking" (transient state), `MergeWhenChecksPassService#process` returns silently without logging, retrying, or rescheduling. The MR remains with auto-merge enabled permanently, but no worker ever picks it up again unless something else triggers `AutoMergeProcessWorker` (e.g., opening the MR page in the UI). ### What is the expected *correct* behavior? When `mergeable?` returns `false` and the merge status is transient ("checking" or "unchecked"), the worker should reschedule itself after a delay to retry the mergeability check. Terminal statuses like "cannot_be_merged" should be logged and not retried. ### Relevant logs and/or screenshots `AutoMergeProcessWorker` completes without errors for stuck MRs: ```json {"class":"AutoMergeProcessWorker","message":"AutoMergeProcessWorker JID-xxx: done: 5.873013 sec","job_status":"done"} ``` No failure, no retry. The worker ran, `mergeable?` returned `false`, and it exited cleanly. There is no log entry at all when `mergeable?` returns `false` -- the `return unless` on line 23 is completely silent. ### Output of checks Self-hosted GitLab, post-17.x. <details> <summary>Expand for output related to GitLab environment info</summary> <pre> Self-hosted GitLab with Sidekiq ConcurrencyLimit middleware (post-17.x). </pre> </details> <details> <summary>Expand for output related to the GitLab application check</summary> <pre> N/A -- all application checks pass. This is a race condition in application code, not an environment issue. </pre> </details> ### Possible fixes The problematic line is [`app/services/auto_merge/merge_when_checks_pass_service.rb`, line 23](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/auto_merge/merge_when_checks_pass_service.rb#L23): ```ruby return unless merge_request.mergeable? # no retry, no reschedule ``` The method does not distinguish between transient statuses ("checking", "unchecked") and terminal statuses ("cannot_be_merged"). Both result in a silent return. Proposed fix: - When `mergeable?` returns `false` and merge status is transient -- reschedule `AutoMergeProcessWorker` after a delay (e.g., 1 minute) with a retry counter - When merge status is terminal -- log the actual status and return - Cap retries (e.g., 5 attempts) to prevent infinite rescheduling Call chain: ``` Pipeline succeeds -> PipelineProcessWorker -> AutoMergeProcessWorker.perform({ pipeline_id: X }) -> AutoMergeService#process(merge_request) -> MergeWhenChecksPassService#process(merge_request) -> merge_request.mergeable? # returns false when status is "checking" -> silent return (BUG) ``` Related files: - `app/workers/auto_merge_process_worker.rb` - `app/services/auto_merge_service.rb` - `app/services/auto_merge/merge_when_checks_pass_service.rb` - `app/services/auto_merge/base_service.rb` ### Patch release information for backports N/A
issue