Class SpringCloudQueryController

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

@RestController @RequestMapping("${axon.springcloud.query-endpoint:/axoniq-springcloud/query}") public class SpringCloudQueryController extends Object
Receives queries sent by other members of the cluster over HTTP, answering them with a stream of responses.

Every member must expose this endpoint under the same path, since that is how members reach each other; the path is the value of the axon.springcloud.query-endpoint property, defaulting to DEFAULT_QUERY_ENDPOINT. Subscription queries are received one level below it, under SUBSCRIPTION_PATH. This controller is registered by the Spring Boot autoconfiguration.

A query is answered with a Server-Sent Events stream rather than one reply, because a query may be answered any number of times. The stream releases the container thread as soon as it is returned, so a member answering a long-running query does not hold one thread per query in flight.

Since:
5.4.0
Author:
Allard Buijze
  • Field Details

    • DEFAULT_QUERY_ENDPOINT

      public static final String DEFAULT_QUERY_ENDPOINT
      The path queries are received under when none is configured.
      See Also:
    • SUBSCRIPTION_PATH

      public static final String SUBSCRIPTION_PATH
      The path, relative to the query endpoint, subscription queries are received under.
      See Also:
  • Constructor Details

    • SpringCloudQueryController

      public SpringCloudQueryController(IncomingQueryInvoker invoker, ScheduledExecutorService scheduler, Executor keepAliveExecutor, SpringCloudQueryControllerConfiguration configuration)
      Constructs a SpringCloudQueryController handing received queries to the given invoker.

      The scheduler only ever decides when an open subscription is due a keep-alive, and never performs the write, so that a subscriber which has stopped reading cannot block whatever else the scheduler carries. The writes run on the keepAliveExecutor instead. Each is a blocking write to one subscriber, so an executor that can hold as many blocked threads as there are open subscriptions suits it, a virtual-thread-per-task executor for instance.

      Parameters:
      invoker - the component invoking this application's local query handler
      scheduler - decides when each open subscription is due a keep-alive
      keepAliveExecutor - performs the keep-alive writes
      configuration - the SpringCloudQueryControllerConfiguration holding how long a response stream may stay open and how often an idle subscription is written to
  • Method Details

    • receiveQuery

      @PostMapping(produces="text/event-stream") public org.springframework.web.servlet.mvc.method.annotation.SseEmitter receiveQuery(@RequestBody QueryDispatchRequest request)
      Handles the given request, sent by another member of the cluster.
      Parameters:
      request - the query sent by another member
      Returns:
      the stream carrying the responses to the query
    • receiveSubscriptionQuery

      @PostMapping(path="/subscription", produces="text/event-stream") public org.springframework.web.servlet.mvc.method.annotation.SseEmitter receiveSubscriptionQuery(@RequestBody SubscriptionQueryRequest request)
      Handles the given subscription request, sent by another member of the cluster.

      The stream carrying it has no timeout: a subscription lasts until the subscriber releases it or this member fails it, and a member that is simply not emitting updates is behaving correctly. What stands in for a timeout is the keep-alive written while it is idle, which stops as soon as the subscriber stops reading.

      Parameters:
      request - the subscription query sent by another member
      Returns:
      the stream carrying the initial result and the updates that follow it