Introduce PartitionedChannel (#8617)
* Introduce `PartitionedChannel` * Implement a `PartitionedChannel` as an extension of the `AbstractExecutorChannel` * Supply this channel with a `PartitionedDispatcher` which is an extension of the `AbstractDispatcher` * The target partition is essentially a `UnicastingDispatcher` with a single thead executor * * Fix language in Javadocs * Add docs for `PartitionedChannel` into `channel.adoc` * Pre-populate partitions in the `PartitionedDispatcher` to ensure a thread number reflection of the partition it is used for (for default `ThreadFactory`) * Add Javadocs to `public` methods * Add Java DSL `PartitionedChannelSpec` and respective factory methods into `Channels` * Use `IntegrationMessageHeaderAccessor.CORRELATION_ID` header as a default partition key * * Fix language in Javadocs * Fix Checkstyle violations * Mark `PartitionedDispatcher.prePopulatedPartitions()` with `synchronized` * * Populate partitions from `PartitionedDispatcher` ctor and when a custom `ThreadFactory` is set * * Clear `executors` in `populatedPartitions()` * * Bring back `synchronized populatedPartitions()` and use it in the `dispatch()`
This commit is contained in:
@@ -203,6 +203,30 @@ CAUTION: The sender can sometimes block.
|
||||
For example, when using a `TaskExecutor` with a rejection policy that throttles the client (such as the `ThreadPoolExecutor.CallerRunsPolicy`), the sender's thread can execute the method any time the thread pool is at its maximum capacity and the executor's work queue is full.
|
||||
Since that situation would only occur in a non-predictable way, you should not rely upon it for transactions.
|
||||
|
||||
[[partitioned-channel]]
|
||||
===== `PartitionedChannel`
|
||||
|
||||
Starting with version 6.1, a `PartitionedChannel` implementation is provided.
|
||||
This is an extension of `AbstractExecutorChannel` and represents point-to-point dispatching logic where the actual consumption is processed on a specific thread, determined by the partition key evaluated from a message sent to this channel.
|
||||
This channel is similar to the `ExecutorChannel` mentioned above, but with the difference that messages with the same partition key are always handled in the same thread, preserving ordering.
|
||||
It does not require an external `TaskExecutor`, but can be configured with a custom `ThreadFactory` (e.g. `Thread.ofVirtual().name("partition-", 0).factory()`).
|
||||
This factory is used to populate single-thread executors into a `MessageDispatcher` delegate, per partition.
|
||||
By default, the `IntegrationMessageHeaderAccessor.CORRELATION_ID` message header is used as the partition key.
|
||||
This channel can be configured as a simple bean:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
PartitionedChannel somePartitionedChannel() {
|
||||
return new PartitionedChannel(3, (message) -> message.getHeaders().get("partitionKey"));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The channel will have `3` partitions - dedicated threads; will use the `partitionKey` header to determine in which partition the message will be handled.
|
||||
See `PartitionedChannel` class Javadocs for more information.
|
||||
|
||||
[[flux-message-channel]]
|
||||
===== `FluxMessageChannel`
|
||||
|
||||
|
||||
@@ -34,6 +34,11 @@ See <<./handler-advice.adoc#context-holder-advice, Context Holder Advice>> for m
|
||||
The `IntegrationFlow` can now end with a convenient `handleReactive(ReactiveMessageHandler)` operator.
|
||||
See <<./reactive-streams.adoc#reactive-message-handler, `ReactiveMessageHandler`>> for more information.
|
||||
|
||||
[[x6.1-partitioned-channel]]
|
||||
==== `PartitionedChannel`
|
||||
A new `PartitionedChannel` has been introduced to process messages with the same partition key in the same thread.
|
||||
See <<./channel.adoc#partitioned-channel, `PartitionedChannel`>> for more information.
|
||||
|
||||
[[x6.1-general]]
|
||||
=== General Changes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user