Skip to content

Optimize service RPC delivery by preferring local handlers#53

Open
NavidMitchell wants to merge 1 commit into
developfrom
claude/quirky-mendel-j8Jxi
Open

Optimize service RPC delivery by preferring local handlers#53
NavidMitchell wants to merge 1 commit into
developfrom
claude/quirky-mendel-j8Jxi

Conversation

@NavidMitchell

Copy link
Copy Markdown
Member

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 localListenerCounts map 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 set localOnly=true on 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 the onDispose callback when the consumer is unregistered, ensuring the tracking stays synchronized with actual handler registration.

  • Comprehensive test coverage: Added DefaultEventBusServiceLocalDeliveryTest with 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

  • Uses ConcurrentHashMap for thread-safe, lock-free tracking of local listeners
  • Uses AtomicBoolean to ensure the unregister decrement happens exactly once, even if onDispose is called multiple times
  • The optimization is transparent to callers and only activates when beneficial (local handler exists)
  • No cluster registry queries needed—purely local state checking for minimal overhead

https://claude.ai/code/session_01QrcYMiSzEbVk9FrukdyS4U

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants