fix(batch): propagate timeout scheduling errors so source events retry (#4749)
## Description Propagate in-memory batch scheduling failures back to the event subscriber so the source event is NACKed and retried. This is a regression from the switch to in-memory buffering. ### Behavior before in-memory buffering Before #3616, a scheduling failure propagated from `AppendAndScheduleBatch` back to the pubsub subscriber: 1. For a new batch, `AppendAndScheduleBatch` called `ScheduleExecution` to enqueue the batch execution job at the configured timeout and returned any enqueue error: https://github.com/inngest/inngest/blob/a5db9793362fc198bcfcb68c71d458ba825e9e6b/pkg/execution/executor/executor.go#L4690-L4703 2. `initialize` wrapped and returned the error from `AppendAndScheduleBatch`: https://github.com/inngest/inngest/blob/a5db9793362fc198bcfcb68c71d458ba825e9e6b/pkg/execution/runner/runner.go#L620 3. `functions` added the initialization error to its returned errors: https://github.com/inngest/inngest/blob/a5db9793362fc198bcfcb68c71d458ba825e9e6b/pkg/execution/runner/runner.go#L522-L529 4. `handleMessage` added the error from `functions` to its returned errors and returned them to the pubsub subscriber: https://github.com/inngest/inngest/blob/a5db9793362fc198bcfcb68c71d458ba825e9e6b/pkg/execution/runner/runner.go#L336-L339 5. The pubsub broker NACKed the message on GCP Pub/Sub: https://github.com/inngest/inngest/blob/a5db9793362fc198bcfcb68c71d458ba825e9e6b/pkg/pubsub/broker.go#L169-L176 The retry was safe because #3590 made a duplicate first event return `BatchNew`, causing another idempotent scheduling attempt. ### Regression introduced by in-memory buffering #3616 enabled in-memory buffering by default and delegated `Append` to the buffer: https://github.com/inngest/inngest/blob/f97285c9e73ce2a60078231e317f4a0161ce3090/pkg/execution/batch/redis.go#L72-L94 The same scheduling failure then stopped inside the buffer: 1. After `BulkAppend` succeeded, `flush` called `handleScheduling`: https://github.com/inngest/inngest/blob/f97285c9e73ce2a60078231e317f4a0161ce3090/pkg/execution/batch/buffer.go#L319 2. `handleScheduling` called `ScheduleExecution`, but a failure was only logged and metered because the function did not return an error: https://github.com/inngest/inngest/blob/f97285c9e73ce2a60078231e317f4a0161ce3090/pkg/execution/batch/buffer.go#L367-L417 3. Although `flush` called both `BulkAppend` and `handleScheduling`, only `BulkAppend` returned an error. `flush` could therefore only set `pending.err` from a `BulkAppend` failure; a scheduling failure still produced a successful pending result: https://github.com/inngest/inngest/blob/f97285c9e73ce2a60078231e317f4a0161ce3090/pkg/execution/batch/buffer.go#L327 4. The successful result was mapped to `BatchAppend` so the executor would not schedule the batch again: https://github.com/inngest/inngest/blob/f97285c9e73ce2a60078231e317f4a0161ce3090/pkg/execution/batch/buffer.go#L353-L364 5. `AppendAndScheduleBatch` received `BatchAppend, nil` and took its no-op branch: https://github.com/inngest/inngest/blob/f97285c9e73ce2a60078231e317f4a0161ce3090/pkg/execution/executor/executor.go#L4668 and https://github.com/inngest/inngest/blob/f97285c9e73ce2a60078231e317f4a0161ce3090/pkg/execution/executor/executor.go#L4681-L4682 6. With no error reaching `handleMessage`, the pubsub broker ACKed the message even though no batch execution job had been enqueued. ### Fix This change restores the original error propagation for in-memory buffered appends: - `scheduleBatchExecution` returns queue scheduling failures: https://github.com/inngest/inngest/blob/d5bb35b90cc078bc1107103bf12d16d379e97c85/pkg/execution/batch/buffer.go#L518 - `handleScheduling` propagates those failures to `flush`: https://github.com/inngest/inngest/blob/d5bb35b90cc078bc1107103bf12d16d379e97c85/pkg/execution/batch/buffer.go#L447 - `flush` sets the error on every affected pending append before notifying its waiter: https://github.com/inngest/inngest/blob/d5bb35b90cc078bc1107103bf12d16d379e97c85/pkg/execution/batch/buffer.go#L364-L370 - `buffer.append` returns the error to `AppendAndScheduleBatch`: https://github.com/inngest/inngest/blob/d5bb35b90cc078bc1107103bf12d16d379e97c85/pkg/execution/batch/buffer.go#L203-L206 - `AppendAndScheduleBatch` returns the error into the existing propagation path to `handleMessage`, causing NACK and redelivery on GCP Pub/Sub: https://github.com/inngest/inngest/blob/d5bb35b90cc078bc1107103bf12d16d379e97c85/pkg/execution/executor/executor.go#L5597-L5603 The successful path still returns `BatchAppend` so scheduling remains owned by the buffer. On retry after a scheduling failure, the existing duplicate handling added in #3675 performs another idempotent scheduling attempt. ## Testing - Updated the scheduling log test to assert that the scheduling error is returned. - Added coverage verifying that `flush` returns a scheduling failure to pending append callers. ## Release note Fixed an issue where transient scheduling failures could prevent a new batch's timeout job from being enqueued, causing the batch to remain pending past its configured timeout until it reached its batch limit. ## Migration note None.
A
albertchae committed
a5133b03f4b109b2a50e205097b4dcd2b995cc34
Parent: 8af0ec2
Committed by GitHub <noreply@github.com>
on 8/14/2026, 6:11:04 PM