@@ -143,13 +143,9 @@ func NewAbortReconciler(repo interfaces.Repository, actionsClient actionsconnect
143143func (r * AbortReconciler ) Run (ctx context.Context ) error {
144144 logger .Infof (ctx , "AbortReconciler starting (%d workers, max %d attempts)" , r .cfg .Workers , r .cfg .MaxAttempts )
145145
146- // Startup scan: enqueue any actions that were left pending from before this process started.
147- if err := r .startupScan (ctx ); err != nil {
148- logger .Errorf (ctx , "AbortReconciler startup scan failed: %v" , err )
149- // Non-fatal — the NOTIFY watcher will still pick up new aborts.
150- }
151-
152- // Start workers.
146+ // Start workers first so they can drain the queue as startupScan fills it.
147+ // If workers started after the scan, a pending-abort count exceeding QueueSize
148+ // would cause push() to block forever (no consumer, full channel).
153149 var wg sync.WaitGroup
154150 for i := 0 ; i < r .cfg .Workers ; i ++ {
155151 wg .Add (1 )
@@ -159,6 +155,12 @@ func (r *AbortReconciler) Run(ctx context.Context) error {
159155 }()
160156 }
161157
158+ // Startup scan: enqueue any actions that were left pending from before this process started.
159+ if err := r .startupScan (ctx ); err != nil {
160+ logger .Errorf (ctx , "AbortReconciler startup scan failed: %v" , err )
161+ // Non-fatal — the NOTIFY watcher will still pick up new aborts.
162+ }
163+
162164 // Watch for new abort requests via NOTIFY (or polling on SQLite).
163165 payloads := make (chan string , 50 )
164166 errs := make (chan error , 10 )
0 commit comments