Class DeliveryOptions
Where and how a push subscription runs its handler, for
MqttSubscriber.subscribe(Subscribe, DeliveryOptions, java.util.function.Consumer).
Instances are immutable and can be shared between subscriptions; they do not define equality.
serial() runs one delivery at a time, in receive order, on an internal thread, as
MqttSubscriber.subscribe(Subscribe, java.util.function.Consumer) does.
withExecutor(Executor) keeps that order but runs each handler on the application's
executor. lanes(Function) runs each delivery on the executor that the application chooses
for its message, its lane: deliveries on the same lane keep that order, and different lanes
can run at the same time. striped(int) keeps that order for deliveries with equal keys, by
default their topics, and runs different keys at the same time on a fixed number of stripes;
each stripe is a lane in what follows. parallel(int) runs up to a given number of
deliveries at the same time in no particular order, as one lane that runs that many at once.
inline() runs one delivery at a time, in receive order, for a handler that returns at
once: the client may run it as part of receiving, and the connection waits for it meanwhile.
Any other handler on an internal thread may block: meanwhile only its own lane waits.
An executor that runs handlers receives at most one task per subscription and lane at a time,
or, for parallel(int), as many as its parallelism. A task runs one delivery's handler and,
while further deliveries wait for the same lane, asks the executor again, so the executor's
queue holds no more tasks than that, and waiting deliveries count against
Subscribe.bufferCapacity() as with an internal thread. While no delivery waits, the
subscription holds none of the executor's threads. The
executor must run each task it accepts, or throw from Executor.execute(Runnable): an
exception of any type ends the delivery that the task would have run as a handler failure
under FailurePolicy.STOP, whatever the subscription's policy, since a refusing executor has
processed nothing. An executor that silently discards a task leaves the subscription waiting
until it closes. An executor that runs tasks on the calling thread, such as a direct executor
or one with a caller-runs policy, keeps the order and the capacity without deepening the
stack.
A failure that stops the client, on any lane, stops the subscription's other lanes too. Failures on other lanes that were already running are logged, and the first failure remains the cause that the client reports.
The application owns the executor; the client never shuts it down. Once the subscription or
the client has closed, a task that the executor still holds does nothing when it runs, so the
tasks that ExecutorService.shutdownNow() returns need not run, and
neither Subscription.terminated() nor MqttClient.terminated() waits for them. They do wait
for a handler still running on the executor.
Acknowledgement follows the request's AckMode wherever the handler runs: AckMode.ON_RECEIVE
just before the handler starts on its executor, and AckMode.AFTER_HANDLER when it returns
there. PUBACK and PUBREC still follow receive order, so a slow handler holds back the
acknowledgement of later deliveries, on other lanes too; see AckMode.
-
Method Summary
Modifier and TypeMethodDescriptionstatic DeliveryOptionsinline()One delivery at a time, in receive order, asserial(), for a handler that returns at once and never waits for this client.static DeliveryOptionslanes(Function<MqttMessage, Executor> selector) Runs each delivery's handler on the executor thatselectorreturns for its message: the delivery's lane.static DeliveryOptionsparallel(int parallelism) Runs up toparallelismdeliveries at the same time, in no particular order.static DeliveryOptionsserial()One delivery at a time, in receive order, on an internal thread: the behavior ofMqttSubscriber.subscribe(Subscribe, java.util.function.Consumer).static DeliveryOptionsstriped(int stripes) Runs deliveries with equal topics one at a time in receive order, and deliveries with different topics possibly at the same time, at moststripesat once.static DeliveryOptionsstriped(int stripes, Function<MqttMessage, ?> key) Likestriped(int), with the key thatkeyreturns for each message in place of its topic; keys are compared with equals and hashCode.withExecutor(Executor executor) Keeps the order, stripes, or parallelism of these options, with each handler running onexecutorinstead of an internal thread.
-
Method Details
-
serial
One delivery at a time, in receive order, on an internal thread: the behavior ofMqttSubscriber.subscribe(Subscribe, java.util.function.Consumer).- Returns:
the options for serial delivery
-
lanes
Runs each delivery's handler on the executor that
selectorreturns for its message: the delivery's lane. Deliveries on the same lane run one at a time in receive order. Lanes are told apart by identity, so return the same executor for the same lane; a new executor object for every message gives every message a lane of its own.The selector runs on an internal thread, once for each delivery in receive order. It receives the message rather than the delivery, so it cannot acknowledge it. An exception or a null result ends that delivery as a handler failure.
- Parameters:
selector- the function that chooses the executor for each message- Returns:
the options for the lanes that `selector` chooses- Throws:
NullPointerException-if `selector` is null
-
striped
Runs deliveries with equal topics one at a time in receive order, and deliveries with different topics possibly at the same time, at moststripesat once. Each topic's deliveries go to one ofstripesfixed stripes that its hash chooses, so different topics can share a stripe and then wait for each other. A stripe runs on an internal thread, or on the executor thatwithExecutor(Executor)sets.- Parameters:
stripes- the number of stripes- Returns:
the options for `stripes` stripes keyed by topic- Throws:
IllegalArgumentException-if `stripes` is less than 1 or greater than 256
-
striped
Likestriped(int), with the key thatkeyreturns for each message in place of its topic; keys are compared with equals and hashCode. The key function runs on an internal thread, once for each delivery in receive order. It receives the message rather than the delivery, so it cannot acknowledge it. An exception or a null result ends that delivery as a handler failure.- Parameters:
stripes- the number of stripeskey- the function that returns the key of each message- Returns:
the options for `stripes` stripes keyed by `key`- Throws:
IllegalArgumentException-if `stripes` is less than 1 or greater than 256NullPointerException-if `key` is null
-
parallel
Runs up toparallelismdeliveries at the same time, in no particular order. Handlers run on internal threads, or on the executor thatwithExecutor(Executor)sets.- Parameters:
parallelism- the largest number of deliveries that run at the same time- Returns:
the options for up to `parallelism` deliveries at the same time- Throws:
IllegalArgumentException-if `parallelism` is less than 1 or greater than 256
-
inline
One delivery at a time, in receive order, as
serial(), for a handler that returns at once and never waits for this client. In return, the client may run the handler as part of receiving its message, rather than hand the delivery to another thread. While such a handler runs, the connection may read nothing else: neither messages for other subscriptions nor the broker's answers to publications, subscriptions, and keep-alive requests.Inside the handler, join() and the get methods of a future that this client returned, or of a future made from one, and the receive methods of this client's pull subscriptions throw
IllegalStateException, even when they would not wait. Read a completed result with getNow, or chain the next step instead. Other waits are not detected: a handler that blocks, or that waits for anything that needs this connection, holds up every subscription of the connection, and one that runs for about the keep-alive interval can lose the connection.A delivery that the client cannot run as part of receiving runs on an internal thread, in the same order and under the same rules. The subscription's buffer, acknowledgement mode, and failure policy work as for
serial().withExecutor(Executor)rejects these options.- Returns:
the options for inline delivery
-
withExecutor
Keeps the order, stripes, or parallelism of these options, with each handler running onexecutorinstead of an internal thread. Replaces an executor chosen earlier.- Parameters:
executor- the executor that runs the handlers- Returns:
options like these that run each handler on `executor`- Throws:
NullPointerException-if `executor` is nullIllegalArgumentException-if these options are [#lanes(Function)], whose selector chooses the executors, or [#inline()], whose handler runs as part of receiving
-