Draft: Fix CoalescingTimer notification loss due to timer auto-drain

Timo Furrer
2026-04-27T14:23:51Z

Fix CoalescingTimer notification loss due to timer auto-drain

In Go 1.23+, time.Timer.Reset auto-drains any fired-but-unread value from the channel before resetting. This causes a race in the poll-and-notify pattern used by WorkerManager: when a producer calls Reset(0) to wake the poller, the value may sit in the channel briefly. If the poller's next loop iteration calls Reset(pollInterval) before reading from C, the auto-drain silently consumes the notification and the poller blocks for the full interval instead.

This manifested as flaky failures in TestConcurrentActivities_OneFails: two activities complete near-simultaneously, the first triggers a warm resume, the second creates a pending workflow task and notifies. After the warm resume yields and suspends, the post-suspension notification is drained by the poller's Reset(5s), so the second task sits unclaimed for 5 seconds -- exceeding the test's awaitExecutionState timeout.

Track pending notifications with a flag under the existing mutex. Reset(0) sets it; Reset(d>0) checks it and overrides d to 0 so the consumer wakes promptly regardless of auto-drain.

Relates to Build PoC of AutoFlow on PostgreSQL (#821).