fix: Materializer startup race with consumer dying #3721
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Race Condition Analysis: Materializer Startup Race
Executive Summary
A race condition exists in the Materializer startup sequence where the Materializer can crash with
an exit (
:noproc) if the Consumer process dies between the snapshot becoming ready and the Materializerattempting to subscribe to it.
The Bug
Location
lib/electric/shapes/consumer/materializer.ex:105-119- Materializer startup sequencelib/electric/shapes/consumer.ex:57-61-subscribe_materializerfunctionRoot Cause
The Materializer's
handle_continue(:start_materializer, ...)performs three operations in sequence:If the Consumer dies between steps 1 and 2 (or 2 and 3), the subsequent calls fail catastrophically.
The Race Window
Impact
exit :noprocTriggers
This race can be triggered when:
Recommended Fixes
Option A: Wrap calls in try/catch with graceful shutdown
Option B: Atomic subscription with monitoring
Option C: Check Consumer existence before each step
Formal Verification
See
MaterializerRace.leanfor a Lean 4 model proving:Code Locations
lib/electric/shapes/consumer/materializer.ex:105-119- Startup sequencelib/electric/shapes/consumer.ex:57-61- subscribe_materializer functionlib/electric/shapes/consumer.ex:64-67- whereis function