Implement watch-triggered callback recovery for bypassed updates#1
Conversation
|
[CI/CD Fix Attempt 1] Fixed a bug in Watch-Triggered Callback Recovery where intercepting bypassed notifications didn't remove all matching deferred updates from the queue. This led to exactly-once semantics being violated because the background refresh loop would incorrectly fire additional duplicate callbacks for any remaining queued states for that namespace. The code now iterates and removes all matching entries from the queue before returning. |
|
[CI/CD Fix Attempt 1] The In the initial implementation ( The issue was fixed by changing the queue removal logic to a filtering pattern (as pushed in Tested locally via |
…s on watch events
|
[CI/CD Fix Attempt 3] The previous fix in This fix unconditionally clears all deferred updates for the matching namespace from the queue whenever a watch event arrives (either intercepted or applied normally). It also guarantees exactly-once semantics by ensuring that the |
Problem Statement
During active push-based configuration synchronization, on-demand read-throughs update the local configuration cache early. When the subsequent push notification (watch event) finally arrives, it is silently ignored because the cache version is already up-to-date or newer.
This causes critical namespace callbacks (such as those responsible for tearing down stale pollers, routing traffic, and orchestrating background workers) to be permanently bypassed. This leaves system states, failover routes, and background workers stale.
Solution & Design Decisions
To solve this without introducing resource-intensive background polling loops or timers, we implement Watch-Triggered Callback Recovery.
Key design decisions include:
curEntry.NotificationVersion() >= ns.NotificationVersion()), we intercept this event rather than dropping it.r.stateChangedDuringReadthrough, we trigger the associated callbacks immediately. This execution occurs inline inside the push notification processor thread (processWatchEvent), achieving sub-50ms latency for propagation.r.stateChangedDuringReadthroughimmediately within the samensMapsLockcritical section where the match is identified.Changes
common/namespace/nsregistry/registry.go:updateSingleNamespaceto return both a boolean indicating if callbacks should run, and the actual*namespace.Namespaceinstance to use for callback execution.nsMapsLock.common/namespace/nsregistry/registry_watch_test.go:TestWatchTriggeredCallbackRecoveryto simulate the concurrent update race, verifying immediate execution upon watch catch-up and zero duplicate triggers.