Skip to content

Commit 1f7f628

Browse files
authored
Update README.md
1 parent f80ebdb commit 1f7f628

1 file changed

Lines changed: 16 additions & 36 deletions

File tree

README.md

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
[![Maven Central](https://img.shields.io/maven-central/v/io.github.q3769/conseq4j.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22io.github.q3769%22%20AND%20a:%22conseq4j%22)
23

34
# conseq4j
@@ -93,16 +94,12 @@ public interface ExecutorServiceFactory {
9394
}
9495
```
9596

96-
This API style loosely takes the form of "thread affinity". Sequence keys are used to summon executors of JDK
97-
type [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html). The same
98-
sequence key always gets back the same sequential executor. All tasks of that sequence key can then be "affined" to and
99-
executed sequentially by the summoned executor in the same submission order.
97+
This API style loosely takes the form of "thread affinity". Sequence keys are used to summon executors of the [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) JDK
98+
type. The same sequence key always gets back the same sequential executor. All tasks of that sequence key can then be "affined" to and executed sequentially by the summoned executor in the same submission order.
10099

101-
The total number of executors concurrently available at runtime is configurable. As each executor is sequential, the
102-
number of available executors equals the number of tasks that can be executed in parallel.
100+
The total number of executors concurrently available at runtime is configurable, and default to the available runtime processors of the JVM. Since each executor is sequential, the number of available executors equals the number of tasks that can be executed in parallel.
103101

104-
Consider using this style when the summoned executor needs to provide
105-
the [syntax and semantic richness](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#method.summary)
102+
Consider using this style when the summoned executor needs to provide the [syntax and semantic richness](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#method.summary)
106103
of the JDK `ExecutorService` API.
107104

108105
- Sample usage
@@ -148,18 +145,11 @@ As with hashing, collision may occur among different sequence keys. When hash co
148145
sequence keys are assigned to the same executor. Due to the single-thread setup, the executor still ensures the local
149146
sequential execution order for each individual sequence key's tasks. However, unrelated tasks of different sequence
150147
keys now assigned to the same bucket/executor may delay each other's execution inadvertently while waiting in the
151-
executor's task queue. Consider this a trade-off of the executor's having the same syntax and semantic richness as a
152-
JDK [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html).
148+
executor's task queue. Consider this a trade-off of getting the syntax and semantic richness of the JDK [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html).
153149

154-
To account for hash collision, conseq4j Style 1 does not support any shutdown action on the API-provided
155-
executor ([ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html))
156-
instance. That is to prevent unintended task cancellation across different sequence keys.
157-
The [Future](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html) instance(s) subsequently
158-
returned by the executor, though, is still cancellable. The hash collision may not be an issue for workloads that are
159-
asynchronous and focused on overall through-put, but is something to be aware of.
150+
To account for hash collision, this `conseq4j` style does not support any shutdown action on its provided executor ([ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)) instances (It'd throws a runtime exception). That is to prevent unintended task cancellation across different sequence keys in the same bucket. The [Future](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html) instances subsequently produced by the executor, however, are still cancellable. The hash collision may not be an issue for workloads that are asynchronous and focused on overall through-put, but is something to be aware of.
160151

161-
The default general concurrency is the JVM
162-
run-time's [availableProcessors](https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors--):
152+
The default general concurrency is the JVM run-time's [availableProcessors](https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors--):
163153

164154
```jshelllanguage
165155
ConseqFactory.instance();
@@ -208,12 +198,8 @@ This API style is more concise. Bypassing the JDK ExecutorService API, it servic
208198
execution semantics holds: Tasks of the same sequence key are executed in the same submission order; tasks of different
209199
sequence keys are managed to execute in parallel.
210200

211-
For versions requiring Java 21+, conseq4j Style 2 defaults to have no preset limit on the overall concurrency when
212-
executing tasks; for other versions, this style's default concurrency is the number of JVM run-time'
213-
s [availableProcessors](https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors--). Prefer
214-
this style when the full-blown syntax and semantic support of
215-
JDK [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) is not
216-
required.
201+
For versions requiring Java 21+, this `conseq4j` style defaults to have no preset limit on the overall concurrency when
202+
executing tasks; for other versions, this style's default concurrency is the number of JVM run-time [availableProcessors](https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors--). Prefer this style when the full-blown syntax and semantic support of JDK [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) is not required by the use case.
217203

218204
- Sample usage
219205

@@ -244,17 +230,12 @@ public class MessageConsumer {
244230
}
245231
```
246232

247-
The implementation relies on
248-
JDK's [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) to
249-
achieve sequential execution of related tasks. One single pool of threads is used to facilitate the overall
250-
asynchronous execution. The concurrency to execute unrelated tasks is generally limited only by the backing work
251-
thread pool's capacity, or unlimited in the case of default/virtual thread mode.
233+
The implementation relies on JDK's [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) to achieve sequential execution of related tasks. One single pool of threads is used to facilitate the overall asynchronous execution. The concurrency to execute unrelated tasks is generally limited only by the backing work thread pool's capacity, or "unlimited" in the case of the default/virtual thread mode.
252234

253235
Instead of thread-affinity or bucket hashing, tasks are decoupled from their execution threads. All pooled threads are
254236
anonymous and interchangeable to execute any tasks. Even sequential tasks of the same sequence key may be executed by
255-
different threads, albeit in sequential order. When the work thread pool has idle threads available, a task awaiting
256-
execution must have been blocked only by its own related task(s) of the same sequence key - as is necessary, and not
257-
by unrelated tasks of different sequence keys in the same "bucket" - as is unnecessary. This can be a desired
237+
different threads, albeit in sequential order. When the work thread pool has idle threads available, yet a task is still awaiting
238+
execution, then the task must have been blocked only by its own related task(s) of the same sequence key - as is necessary, and not by unrelated tasks of different sequence keys in the same "bucket" - as is unnecessary. This can be a desired
258239
advantage over the thread-affinity API style, at the trade-off of lesser syntax and semantic richness than the
259240
JDK [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html).
260241

@@ -297,18 +278,17 @@ out of order in a globally concurrent process. This implies:
297278
received.
298279

299280
(3) The message consumer ensures that related messages are processed in the same order, e.g. by using a
300-
sequence/correlation key as with this API.
281+
sequence/correlation key, as with the `conseq4j` API.
301282

302283
### 2. Curative
303284

304285
This is more on the business rule level. Sometimes preventative measures are either not possible or not worthwhile to
305286
pursue. By the time messages arrive at the consumer, they may be intrinsically out of order. E.g. when the messages are
306-
coming in from independent producers and sources, there may be no guarantee of correct ordering in the first place. In
307-
such cases, the message consumer may be able to take a curative approach, by applying business rules to restore
287+
coming in from independent producer and source systems, there may be no guarantee of correct ordering in the first place. In such cases, the message consumer may be able to take a curative approach, by applying business rules to restore
308288
necessary order and properly handle the out-of-order messages.
309289

310290
Compared to preventative measures, corrective ones can be much more complicated in terms of design, implementation and
311-
runtime performance. E.g. for each incoming event, it may help to do a stateful/historical look-up of all the data and
291+
runtime performance. E.g. for each incoming event, it may help to perform a stateful/historical look-up of all the data and
312292
other events that are related; this forms a correlated and collective information session of the incoming event. A
313293
comprehensive review of such session can detect and determine if the incoming event is out of order per business rules;
314294
corrective measures can then be taken to restore the right order, among other reactive actions. This may fall into the

0 commit comments

Comments
 (0)