Class IncomingQueryInvoker

java.lang.Object
io.axoniq.framework.springcloud.query.IncomingQueryInvoker

public class IncomingQueryInvoker extends Object
Turns a QueryDispatchRequest received from another member into an invocation of this application's local query handler, writing every response it produces to a QueryResponseSink.

This invoker is a component of its own, separate from the endpoint receiving the request, for the same reasons its command counterpart is: the endpoint is a Spring bean built before the connector, while the handler it invokes only exists once DistributedQueryBus registers one, later still. The connector binds the handler here when it receives it. Keeping the work here also means the whole receiving path is testable without standing up a web stack.

A request arriving before a handler is bound is answered with a QueryErrorCode.NO_HANDLER_FOR_QUERY failure, which the dispatching member sees as a transient one: this member is still starting up, and will be able to answer shortly.

Since:
5.4.0
Author:
Allard Buijze
  • Constructor Details

    • IncomingQueryInvoker

      public IncomingQueryInvoker(Supplier<String> memberName, @Nullable MessageConverter converter)
      Constructs an IncomingQueryInvoker reporting failures as originating from the member the given memberName supplies.

      Taken as a supplier because a member is not named until it has registered with discovery, which happens after this invoker is built. Resolving it per failure reports the name this member is actually known by, rather than the provisional one it had at start-up.

      Parameters:
      memberName - supplies the name identifying this application in the failures it reports, used to point at the member a failure originated on.
      converter - the converter attached to received queries for inline payload conversion, and used to serialize application-specific exception details, or null when none is available.
  • Method Details

    • bind

      public void bind(QueryBusConnector.Handler handler)
      Binds the handler that incoming queries are to be invoked on, replacing any previously bound one.
      Parameters:
      handler - the handler to invoke incoming queries on
    • handle

      public void handle(QueryDispatchRequest request, QueryResponseSink sink)
      Handles the given request, received from another member, writing its responses to the given sink.

      Returns as soon as the query has been handed to the local handler. Responses are written to the sink as the handler produces them, which for a handler that answers asynchronously is after this method returned.

      Parameters:
      request - the request received from another member
      sink - receives the responses to the query, and the outcome that ends them
    • handleSubscription

      public void handleSubscription(SubscriptionQueryRequest request, QueryResponseSink sink)
      Handles the given subscription request, received from another member, writing every update the query produces on this member to the given sink.

      Carries updates alone. The initial result of a subscription query is a query like any other, and the subscribing member asks for it separately once every member has registered its subscription -- which is what keeps an update emitted while that result is being produced from being missed.

      Every member advertising the query's name receives one of these, because an update is emitted on whichever member's state changed and only reaches subscriptions that member holds a registration for.

      The registration is cancelled when the sink reports it can no longer be written to, so a subscriber that goes away does not leave this member emitting into nothing.

      Parameters:
      request - the subscription query received from another member
      sink - receives the updates, and the outcome that ends them
    • leave

      public void leave()
      Tells every subscriber this member is still answering that it is leaving, and ends each of those subscriptions. Subscriptions received from then on are answered the same way straight away.

      Called when this member stops, once nothing on it emits updates anymore. Each subscriber then ends only this member's part in its subscription and carries on with the members that remain, which is what sets a clean departure apart from a lost connection: after a lost connection the subscriber cannot know which updates it missed, and fails the subscription. Ending the streams is also what releases them, so the web container does not wait on them while shutting down.

      Calling this more than once is harmless: a subscription is only ended once.

    • rejoin

      public void rejoin()
      Accepts subscriptions again after a leave(), for a member that is started again after it stopped.

      Subscriptions ended by leaving stay ended: their subscribers have already carried on without this member, and learn it is back from it advertising the query again.