whole bunch of fixes and features #7
Reference in New Issue
Block a user
Delete Branch "neuralwatt-router-service"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fix: guard
publish_decisionagainst concurrent subscriber churnProblem
publish_decision()was iterating_sse_loopsoutside the_subscribers_lock, contradicting its own doc-comment that states the subscriber snapshot must be taken while holding the lock. This creates a real race:subscribe()can add an SSE loop to the set mid-iteration → unbounded iteration (new subscriber keeps the iterator alive).unsubscribe()can remove/drop a loop mid-iteration → RuntimeError: set changed size during iteration.dispatcher._stream_route_decisions()that callsevents.unsubscribe()from a background thread can collide with the iteration.Fix
_subscribers_lock, snapshotlist(_sse_loops), release. Iterate the snapshot in the outer scope._subscriber_loop.close()and_sse_loops.discard()now acquires_subscribers_lockbefore mutating (mirrors the path indispatcher._stream_route_decisions()so the two halves never race).call_soon_threadsafe()outside lock — the event fan-out usesloop.call_soon_threadsafe()which is already thread-safe and does not require holding the inner lock; the lock is already released for the broadcast loop.Test
Added
test_concurrent_subscribe_unsubscribe_during_publish— a background thread callssubscribe()/unsubscribe()rapidly (500 round-trips) in parallel with apublish_decision()call, asserting noRuntimeErrorfrom set-changed-during-iteration.Verification
The {"label": "quota", "value": "N/A (plan not set)"} row in build_model was never consumed by the renderer, which only looks up plan_kwh/metered_kwh_30d/fraction/calls/reset_date. Return an empty list when quota is null instead of producing dead data.fix: resolve outstanding code review findings (baseline report, SSE cleanup, flex-preference)to fix(events): guard publish_decision against concurrent subscriber churnfix(events): guard publish_decision against concurrent subscriber churnto whole bunch of fixes and features