Skip to content

Lost-wakeup race in the Logs/Metrics batch processor can strand queued events past the flush interval #5739

Description

@tsushanth

Description

The add -> maybeSchedule fast path reads the hasScheduled flag outside scheduleLock, while the running flush resets that flag inside scheduleLock after a separate queue.isEmpty() check. This is a check-then-act TOCTOU: an event offered by a producer thread in the window after the flush reads isEmpty() == true but before it writes hasScheduled = false is neither observed by the flush (not rescheduled) nor able to schedule itself (the fast path sees hasScheduled still true). The event is left queued with hasScheduled == false and no pending flush. Affects both LoggerBatchProcessor and MetricsBatchProcessor (byte-identical scheduling logic).

Root cause

  • sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java: maybeSchedule reads hasScheduled outside the lock; flush() re-checks isEmpty() then sets hasScheduled = false inside the lock.
  • sentry/src/main/java/io/sentry/metrics/MetricsBatchProcessor.java: same structure.

The stranded event is only sent on a subsequent add() or an explicit flush()/close(). On Android this is partly masked because AndroidLoggerBatchProcessor/AndroidMetricsBatchProcessor force a flush on onBackground().

Note: reproduced as a deterministic interleaving of the state machine (same volatile flag, ReentrantLock, ConcurrentLinkedQueue), not a live Android run.

Suggested fix

Make the flag reset and queue re-check safe against the lock-free producer path: after draining, set hasScheduled = false first and then re-check queue.isEmpty() under the lock (rescheduling if non-empty), or remove the lock-free fast path so maybeSchedule always consults the queue under scheduleLock.

Metadata

Metadata

Assignees

No one assigned

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Waiting for: Product Owner

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions