Optimize service RPC delivery by preferring local handlers#53
Open
NavidMitchell wants to merge 1 commit into
Open
Optimize service RPC delivery by preferring local handlers#53NavidMitchell wants to merge 1 commit into
NavidMitchell wants to merge 1 commit into
Conversation
Service RPCs travel over the Vert.x clustered event bus addressed to the service's base resource. The point-to-point selector round-robins sends across every node registered for that address, so when a node hosts a service locally and the same service is also registered elsewhere, ~half of that node's own calls get shipped to a remote node for no reason. Track the addresses this node hosts a local handler for in a reference counted map, populated where the consumer's handler is attached in _listen and cleared (once) when it is unregistered, so membership means "a local consumer exists at this address on this node". On the send path, set DeliveryOptions.setLocalOnly(true) for point-to-point service sends whose base resource is locally hosted, which bypasses the cluster selector and delivers to the local handler. It is gated on the service scheme and only fires when a local handler exists, so it never misroutes and never trips NO_HANDLERS. The per-message check is a lock free containsKey plus a scheme check, no cluster or registry query. Works on Vert.x 4 and 5 (localOnly is the version-agnostic lever after Vert.x 5 removed the pluggable NodeSelector SPI). https://claude.ai/code/session_01QrcYMiSzEbVk9FrukdyS4U
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
This change optimizes the event bus to prefer local delivery for service RPC calls when a handler is already registered on the current node, avoiding unnecessary cluster hops in clustered deployments.
Key Changes
Local listener tracking: Added a
localListenerCountsmap to track which service addresses have local handlers registered on this node. The count is incremented when a consumer is attached and decremented when unregistered, ensuring accurate tracking of local handler availability.Local delivery preference: Modified
createDeliveryOptions()to setlocalOnly=trueon delivery options for service scheme sends when a local handler exists for the target address. This bypasses the cluster's round-robin selector and delivers directly to the local handler.New predicate method: Added
shouldPreferLocalDelivery()to determine if a send should use local-only delivery. It checks both that the event uses the service destination scheme and that a local handler is registered for the address.Lifecycle coupling: The local listener count is incremented in
_listen()when the consumer handler is attached and decremented in theonDisposecallback when the consumer is unregistered, ensuring the tracking stays synchronized with actual handler registration.Comprehensive test coverage: Added
DefaultEventBusServiceLocalDeliveryTestwith four test cases covering: local delivery preference when handler exists, no preference when handler doesn't exist, no preference for non-service schemes, and proper cleanup when handlers are unregistered.Implementation Details
ConcurrentHashMapfor thread-safe, lock-free tracking of local listenersAtomicBooleanto ensure the unregister decrement happens exactly once, even ifonDisposeis called multiple timeshttps://claude.ai/code/session_01QrcYMiSzEbVk9FrukdyS4U