Skip to content

fix(batcher): Reset lock and flusher in child after fork#6163

Merged
ericapisani merged 7 commits intomasterfrom
py-2391-fix-deadlock-in-batcher-k4wvs
Apr 30, 2026
Merged

fix(batcher): Reset lock and flusher in child after fork#6163
ericapisani merged 7 commits intomasterfrom
py-2391-fix-deadlock-in-batcher-k4wvs

Conversation

@ericapisani
Copy link
Copy Markdown
Member

@ericapisani ericapisani commented Apr 28, 2026

Apply the same fork-safety fix introduced in #6148 (for the monitor) to all batchers (log, metrics, span).

If os.fork() runs while another thread holds Batcher._lock, the child inherits the lock locked but the holding thread does not exist in the child, so the lock can never be released and _ensure_thread deadlocks forever. Register an after-fork hook via os.register_at_fork that replaces _lock with a fresh lock and resets _flusher / _flusher_pid in the child. The hook holds a weakref to the batcher so it does not keep the instance alive.

Each batcher (log, metrics, span) gets a regression test that acquires the lock on the parent, forks, and asserts in the child that the lock object was replaced, the new lock is not held, and _flusher / _flusher_pid were reset. Tests are skipped on Windows and on Python builds without os.register_at_fork.

Fixes PY-2391
Fixes #6149

Uses the same fix introduced in #6148 to prevent deadlocks in the
monitor when os.fork() is called while another thread holds the
monitor's lock.

If os.fork() runs while another thread holds Batcher._lock, the child
inherits the lock locked but the holding thread does not exist in the
child, so the lock can never be released and _ensure_thread deadlocks
forever. Register an after-fork hook via os.register_at_fork that
replaces _lock with a fresh lock and resets _flusher / _flusher_pid
in the child. Use a weakref to the batcher so the hook does not keep
the instance alive.

Move shared init out of SpanBatcher into the base Batcher.__init__ so
all batchers (log, metrics, span) get the fork-safety hook from a
single place.

Fixes PY-2391
Fixes #6149
@linear-code
Copy link
Copy Markdown

linear-code Bot commented Apr 28, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

Codecov Results 📊

13 passed | Total: 13 | Pass Rate: 100% | Execution Time: 7.93s

All tests are passing successfully.

❌ Patch coverage is 40.00%. Project has 14925 uncovered lines.

Files with missing lines (2)
File Patch % Lines
_batcher.py 61.68% ⚠️ 41 Missing and 5 partials
_span_batcher.py 81.19% ⚠️ 19 Missing and 9 partials

Generated by Codecov Action

…class from batcher but that will not be done in this set of changes. Update batcher deadlock fix to use weakmethod, to be consistent with the approach taken in monitor.py
@ericapisani
Copy link
Copy Markdown
Member Author

bugbot run

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b5073b2. Configure here.

Comment thread sentry_sdk/_span_batcher.py
@ericapisani ericapisani marked this pull request as ready for review April 29, 2026 14:31
@ericapisani ericapisani requested a review from a team as a code owner April 29, 2026 14:31
Comment thread sentry_sdk/_span_batcher.py
Comment thread sentry_sdk/_batcher.py
Comment thread sentry_sdk/_batcher.py
@ericapisani ericapisani merged commit b5735ab into master Apr 30, 2026
156 checks passed
@ericapisani ericapisani deleted the py-2391-fix-deadlock-in-batcher-k4wvs branch April 30, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Possible deadlock when using Batcher and os.fork()

2 participants