Skip to content

pollerBalancer.balance can unnecessarily block due to non-deterministic map iteration #2236

@yuandrew

Description

@yuandrew

Expected Behavior

When a poller type's count drops to <= 0, balance() should return nil immediately, indicating the poller has no pending polls and should not block.

Actual Behavior

On subsequent iterations of the outer loop (after waiting on a barrier), Go's non-deterministic map iteration may visit another poller type with count == 0 before visiting the current poller type. This causes the function to grab that other type's barrier and block on it, even though the current poller type's own count is <= 0 and should have triggered a return nil.

The poller remains unnecessarily blocked until either a poller of the other type starts (closing the barrier) or the context is cancelled.

https://github.com/temporalio/sdk-go/blob/3f64d34e51f41f6d38c18b4a922da660b187f3c8/internal/internal_worker_base.go

Steps to Reproduce the Problem

  1. Have two registered poller types (e.g., sticky and non-sticky).
  2. A poller enters balance() with its type's count > 0, sees the other type has count == 0, and blocks on its barrier.
  3. While blocked, all other pollers of the same type finish, decrementing its count to 0.
  4. The other type's barrier fires (someone starts a poller of that type). The blocked poller re-acquires the lock and re-enters the inner loop.
  5. Due to random map iteration, the loop visits the other type (which now has count == 0 again) before the current type — grabs the barrier and blocks again instead of returning nil.

Specifications

  • Version:
  • Platform:

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions