fix(batcher): Serialize flushed items outside the batcher lock - #7776
NicoHinderling wants to merge 1 commit into
Conversation
Batcher._flush held its lock while serializing buffered items. Serializing can trigger GC, and a finalizer that logs then needs the logging handler lock, which another thread holds while waiting for the batcher lock in add(). Swap the buffer out under the lock and build the envelope after releasing it. Fixes #7775
|
(this was auto generated on behalf of that ticket i reported.. feel free to close this, if you would prefer to address it in a different way, I just opened it in case it's helpful) |
Codecov Results 📊✅ 129739 passed | ❌ 2 failed | ⏭️ 7169 skipped | Total: 136910 | Pass Rate: 94.76% | Execution Time: 434m 16s 📊 Comparison with Base Branch
➕ New Tests (2)View new tests
➖ Removed Tests (1)View removed tests
❌ Failed Tests
|
|
Thanks @NicoHinderling. |
|
Right this could actually work since |
Batcher._flushheld_lockwhile serializing the buffered items. Serializing can trigger GC, and if a collected object's finalizer logs, the flush thread needs the logging handler lock, which another thread already holds while it waits for_lockinadd(). That lock-order inversion freezes every later log call in the process; it's what was hard-killing Seer's Celery tasks (#7775)._flushnow swaps the buffer out under the lock (the replacement list is allocated before taking it) and builds the envelope after releasing it. Applies toLogBatcherandMetricsBatcher.SpanBatcher._flushserializes under its own lock the same way, andadd()calls_record_lostunder the lock once the buffer is full. Happy to follow up on both.Fixes #7775