Class SpringCloudQueryBusConnector

java.lang.Object
io.axoniq.framework.springcloud.query.SpringCloudQueryBusConnector
All Implemented Interfaces:
QueryBusConnector, DescribableComponent

public class SpringCloudQueryBusConnector extends Object implements QueryBusConnector
A QueryBusConnector distributing queries over the members a Spring Cloud discovery implementation reports.

Where a command is routed to one member by its routing key, a query asks nothing of where it is handled: any member advertising the query's name may answer it. Successive queries of a name therefore rotate over the members advertising it, spreading the load rather than sending every one to the same member.

A query is answered with a stream of responses rather than a single result, so the responses arrive as they are produced. A member answering faster than this application consumes fails the query rather than buffering without limit; see HttpRemoteQueryDispatcher.

A subscription query reaches every member advertising its name, not just the one a plain query would route to: an update is emitted on whichever member's state changed, and only reaches subscriptions that member holds a registration for. One of them answers the initial result as well, so a subscriber gets one initial result and the updates of the whole cluster. The initial result is asked for only once every one of those members has registered the subscription, so that an update emitted in the meantime reaches the subscriber rather than nobody. A member that starts advertising the query while a subscription is active fails that subscription rather than joining it late; see SubscriptionQueryMembersChangedException.

Since:
5.4.0
Author:
Allard Buijze
  • Constructor Details

    • SpringCloudQueryBusConnector

      public SpringCloudQueryBusConnector(SpringCloudMemberDiscovery discovery, IncomingQueryInvoker invoker, RemoteQueryDispatcher dispatcher, @Nullable MessageConverter converter)
      Constructs a SpringCloudQueryBusConnector routing with the given discovery.
      Parameters:
      discovery - the discovery reporting which members handle which queries
      invoker - the invoker queries arriving from other members are handled through
      dispatcher - the dispatcher sending queries to other members
      converter - the converter attached to queries routed to this application, so that a locally routed query carries the same conversion capability as one that travelled over the wire, or null when none is available.
  • Method Details

    • query

      public MessageStream<QueryResponseMessage> query(QueryMessage query, @Nullable ProcessingContext context)
      Description copied from interface: QueryBusConnector
      Sends the given query to the remote QueryBus.
      Specified by:
      query in interface QueryBusConnector
      Parameters:
      query - The query to send to the remote QueryBus.
      context - The context, if available, in which the query is generated
      Returns:
      the stream of responses for the query
      See Also:
    • start

      public void start()
      Prepares this connector for dispatching queries, after a previous shutdownDispatching() if any, and for answering subscriptions again, after a previous disconnect() if any.

      Performed in the Phase.INBOUND_QUERY_CONNECTOR phase.

    • disconnect

      public CompletableFuture<Void> disconnect()
      Stops advertising the queries this member handles, and tells the subscribers it is still answering that it is leaving.

      Performed in the Phase.INBOUND_QUERY_CONNECTOR phase, before dispatching is shut down, so that other members learn this member is leaving while it can still answer what is already in flight.

      Announcing it here is safe because shutdown reaches Phase.INBOUND_EVENT_CONNECTORS, where event processors are stopped, before it reaches this phase. Nothing is left that could emit an update onto a subscription by the time they are ended, so no subscriber misses one. Where a web server would cut the subscriptions' streams before this phase, as Spring Boot's does, the announcement has to be made earlier; it is only made once, so the announcement here then finds nothing left to end.

      Returns:
      a future that completes once this member no longer advertises any query, and answers no subscription
    • shutdownDispatching

      public CompletableFuture<Void> shutdownDispatching()
      Stops dispatching new queries, and waits for the responses to the ones already dispatched.

      Performed in the Phase.OUTBOUND_QUERY_CONNECTORS phase.

      Returns:
      a future that completes once every dispatched query has been answered
    • subscriptionQuery

      public MessageStream<QueryResponseMessage> subscriptionQuery(QueryMessage query, @Nullable ProcessingContext context, int updateBufferSize)
      Description copied from interface: QueryBusConnector
      Sends the given query to the remote QueryBus.
      Specified by:
      subscriptionQuery in interface QueryBusConnector
      Parameters:
      query - The query to send to the remote QueryBus.
      context - The context, if available, in which the query is generated
      updateBufferSize - The size of the buffer used to store update for the subscription query.
      Returns:
      the stream of responses for the query
      See Also:
    • subscribe

      public CompletableFuture<Void> subscribe(QualifiedName queryName)
      Description copied from interface: QueryBusConnector
      Subscribes this connector to queries matching the given name.

      A connector serves queries of a given name with a single handler. Subscribing a name this connector is already subscribed to therefore has no further effect, and completes as soon as the subscription that is already in place is acknowledged. A single unsubscribe of that name undoes any number of subscriptions to it.

      Specified by:
      subscribe in interface QueryBusConnector
      Parameters:
      queryName - The QualifiedName of the Message.type() to subscribe to.
      Returns:
      A CompletableFuture that completes successfully when this connector subscribed to the given name.
    • unsubscribe

      public boolean unsubscribe(QualifiedName queryName)
      Description copied from interface: QueryBusConnector
      Unsubscribes this connector from queries with the given name.

      Undoes any number of subscriptions to the given name, leaving no query of that name routed to this connector.

      Specified by:
      unsubscribe in interface QueryBusConnector
      Parameters:
      queryName - The QualifiedName of the Message.type() to unsubscribe from.
      Returns:
      true if unsubscribing was successful, false otherwise.
    • onIncomingQuery

      public void onIncomingQuery(QueryBusConnector.Handler handler)
      Description copied from interface: QueryBusConnector
      Registers a handler to process incoming query messages.
      Specified by:
      onIncomingQuery in interface QueryBusConnector
      Parameters:
      handler - The handler responsible for managing incoming queries.
    • describeTo

      public void describeTo(ComponentDescriptor descriptor)
      Description copied from interface: DescribableComponent
      Describe the properties of this DescribableComponent with the given descriptor.

      Components should call the appropriate describeProperty methods on the descriptor to register their properties. The descriptor is responsible for determining how these properties are formatted and structured in the final output.

      Best Practices: As a general rule, all relevant fields of a DescribableComponent implementation should be described in this method. However, developers have discretion to include only the fields that make sense in the context. Not every field may be meaningful for description purposes, especially internal implementation details. Furthermore, components might want to expose different information based on their current state. The final decision on what properties to include lies with the person implementing the describeTo method, who should focus on providing information that is useful for understanding the component's configuration and state.

      Example implementation:

       public void describeTo(ComponentDescriptor descriptor) {
           descriptor.describeProperty("name", this.name);
           descriptor.describeProperty("enabled", this.enabled);
           descriptor.describeProperty("configuration", this.configuration); // A nested component
           descriptor.describeProperty("handlers", this.eventHandlers);      // A collection
       }
       
      Specified by:
      describeTo in interface DescribableComponent
      Parameters:
      descriptor - The component descriptor to describe this DescribableComponentn its properties in.