Reduce ExpirePipelineCacheService load on the database by fixing unnecessary cache invalidations
## Problem In https://gitlab.com/gitlab-com/gl-infra/production/-/work_items/21562 we found that `ExpirePipelineCacheService` is running ~400 RPS against the CI primary database ([dashboard](https://dashboards.gitlab.net/goto/bfgvx3tua94aoa?orgId=1)). We introduced https://gitlab.com/gitlab-org/gitlab/-/merge_requests/228054 to expire the cache async using the replica nodes, but that didn't reduce the calls to the primary node. The root cause is that `ExpirePipelineCacheService` is also called synchronously from `AtomicProcessingService`, which already executes on the primary database: - `app/services/ci/pipeline_processing/atomic_processing_service.rb` [L43-51](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/ci/pipeline_processing/atomic_processing_service.rb?plain=1#L43-51) This call site was originally async but was switched to synchronous ~5 years ago in [!75611](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75611/diffs), bypassing the background worker routing introduced by the feature flag. Additionally, the cache may be invalidated unnecessarily. The [pipeline model](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/ci/pipeline.rb?plain=1#L327-355) gates invalidation on pipeline status changes, but `AtomicProcessingService` ([L43-51](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/ci/pipeline_processing/atomic_processing_service.rb?plain=1#L43-51)) calls `ExpirePipelineCacheService` unconditionally -- including cases where the pipeline status may not have changed (e.g. replacing a running job with the next running job). The two call sites also appear redundant. If the speculation is correct that the cache does not need to be expired on every `AtomicProcessingService` run, we would expect the ~400 RPS to drop to around ~10 RPS. ## Proposal - Investigate whether the ETag cache expiration call in `AtomicProcessingService` ([L43-51](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/ci/pipeline_processing/atomic_processing_service.rb?plain=1#L43-51)) can be removed entirely, or conditionally called only when the pipeline status actually changes. - Consolidate the two call sites to eliminate redundancy and ensure all cache expiration is routed through the background worker. ### UPDATE [2026-04-14] We can't remove Etag cache expiration in `AtomicProcessingService` because many paths cache more granular data than just pipeline status (https://gitlab.com/gitlab-org/gitlab/-/work_items/594454#note_3191936546). See discussion thread for new proposals in https://gitlab.com/gitlab-org/gitlab/-/work_items/594454#note_3193561359.
issue