{"id":15068761,"url":"https://github.com/vsilaev/tascalate-concurrent","last_synced_at":"2025-04-07T12:10:27.968Z","repository":{"id":57737828,"uuid":"87311158","full_name":"vsilaev/tascalate-concurrent","owner":"vsilaev","description":"Implementation of blocking (IO-Bound) cancellable java.util.concurrent.CompletionStage and related extensions to java.util.concurrent.ExecutorService-s","archived":false,"fork":false,"pushed_at":"2024-04-20T14:32:32.000Z","size":903,"stargazers_count":205,"open_issues_count":0,"forks_count":28,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-10-30T04:49:43.514Z","etag":null,"topics":["async","async-programming","asynchronous","asynchronous-programming","completablefuture","completionstage","concurrency","concurrent","concurrent-programming","executor","executorservice","java","java-library","java11","java8","java9","promise","promise-interface","promise-library","promises"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vsilaev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-05T13:14:18.000Z","updated_at":"2024-10-29T11:39:48.000Z","dependencies_parsed_at":"2022-08-24T12:51:02.685Z","dependency_job_id":"7ef2ed20-7a53-4d52-a982-2f40530e343e","html_url":"https://github.com/vsilaev/tascalate-concurrent","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsilaev%2Ftascalate-concurrent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsilaev%2Ftascalate-concurrent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsilaev%2Ftascalate-concurrent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsilaev%2Ftascalate-concurrent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vsilaev","download_url":"https://codeload.github.com/vsilaev/tascalate-concurrent/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247648977,"owners_count":20972945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","async-programming","asynchronous","asynchronous-programming","completablefuture","completionstage","concurrency","concurrent","concurrent-programming","executor","executorservice","java","java-library","java11","java8","java9","promise","promise-interface","promise-library","promises"],"created_at":"2024-09-25T01:39:10.348Z","updated_at":"2025-04-07T12:10:27.949Z","avatar_url":"https://github.com/vsilaev.png","language":"Java","readme":"[![Maven Central](https://img.shields.io/maven-central/v/net.tascalate/net.tascalate.concurrent.svg)](https://search.maven.org/artifact/net.tascalate/net.tascalate.concurrent/0.9.8/jar) [![GitHub release](https://img.shields.io/github/release/vsilaev/tascalate-concurrent.svg)](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.9.8) [![license](https://img.shields.io/github/license/vsilaev/tascalate-concurrent.svg)](http://www.apache.org/licenses/LICENSE-2.0.txt)\n# tascalate-concurrent\nThe library provides an implementation of the [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html) interface and related classes these are designed to support long-running blocking tasks (typically, I/O bound). This functionality augments the sole Java 8 built-in implementation, [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html), that is primarily supports computational tasks. Also, the library helps with numerous asynchronous programing challenges like handling timeouts, retry/poll functionality, orchestrating results of multiple concurrent computations and similar.\n\nSince the version [0.7.0](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.7.0) the library is shipped as a multi-release JAR and may be used both with Java 8 as a classpath library or with Java 9+ as a module.\n\n**IMPORTANT!**\n\nIn the version [0.8.0](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.8.0) the artifact was renamed:\nNew name:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.tascalate\u003c/groupId\u003e\n    \u003cartifactId\u003enet.tascalate.concurrent\u003c/artifactId\u003e\n    \u003cversion\u003e0.9.8\u003c/version\u003e \u003c!-- Any version above 0.8.0, the latest one is recommended --\u003e\n\u003c/dependency\u003e\n```\nOld Name\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.tascalate.concurrent\u003c/groupId\u003e\n    \u003cartifactId\u003enet.tascalate.concurrent.lib\u003c/artifactId\u003e\n    \u003cversion\u003e0.7.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n# Why a CompletableFuture is not enough?\nThere are several shortcomings associated with [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) implementation that complicate its usage for real-life asynchronous programming, especially when you have to work with I/O-bound interruptible tasks:\n1.\t`CompletableFuture.cancel()` [method](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#cancel-boolean-) does not interrupt underlying thread; it merely puts future to exceptionally completed state. So even if you use any blocking calls inside functions passed to `thenApplyAsync` / `thenAcceptAsync` / etc - these functions will run till the end and never will be interrupted. Please see [CompletableFuture can't be interrupted](http://www.nurkiewicz.com/2015/03/completablefuture-cant-be-interrupted.html) by Tomasz Nurkiewicz.\n2.\tBy default, all `*Async` composition methods of `CompletableFutrure` use `ForkJoinPool.commonPool()` ([see here](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html#commonPool--)) unless explicit [Executor](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html) is specified. This thread pool is shared between all [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)-s and all parallel streams across all applications deployed on the same JVM. This hard-coded, unconfigurable thread pool is completely outside of application developers' control, hard to monitor and scale. Therefore, in robust real-life applications you should always specify your own `Executor`. With API enhancements in Java 9+, you can fix this drawback, but it will require some custom coding.\n3.\tAdditionally, built-in Java 8 concurrency classes provides pretty inconvenient API to combine several [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html)-s. `CompletableFuture.allOf` / `CompletableFuture.anyOf` methods accept only [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) as arguments; you have no mechanism to combine arbitrary [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html)-s without converting them to [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) first. Also, the return type of the aforementioned `CompletableFuture.allOf` is declared as `CompletableFuture\u003cVoid\u003e` - hence you are unable to extract conveniently individual results of the each future supplied. `CompletableFuture.anyOf` is even worse in this regard; for more details please read on here: [CompletableFuture in Action](http://www.nurkiewicz.com/2013/05/java-8-completablefuture-in-action.html) (see Shortcomings) by Tomasz Nurkiewicz.\n4. Support for timeouts/delays was introduced to [CompletableFuture](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/CompletableFuture.html) only in Java 9, so still widely supported applications running on Java 8 are left out without this important functionality. Plus, some design decisions like using delayed executors instead of 'delay' operator, are somewhat questionable.\n\nThere are numerous free open-source libraries that address some of the aforementioned shortcomings. However, none of them provides implementation of interruptible `CompletionStage` and no one solves _all_ of the issues coherently.\n\n# How to use?\nTo use a library you have to add a single Maven dependency\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.tascalate\u003c/groupId\u003e\n    \u003cartifactId\u003enet.tascalate.concurrent\u003c/artifactId\u003e\n    \u003cversion\u003e0.9.8\u003c/version\u003e\n\u003c/dependency\u003e\n```\n# What is inside?\n## 1.\tPromise interface\nThis is the core interface of the Tascalate Concurrent library. It may be best described by the formula: \n```java\nPromise == CompletionStage + Future\n```\nI.e., it combines both blocking [Future](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html)’s API, including `cancel(boolean mayInterruptIfRunning)` [method](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html#cancel-boolean-), _AND_ composition capabilities of [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html)’s API. Importantly, all composition methods of [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html) API (`thenAccept`, `thenCombine`, `whenComplete` etc.) are re-declared to return `Promise` as well.\n\nThe decision to introduce an interface that merges `CompletionStage` and `Future` is aligned with the design of `CompletableFuture` API.  In addition, several useful methods of `CompletableFuture` API are added as well:\n```java\nT getNow(T valueIfAbsent) throws CancellationException, CompletionException;\nT getNow(Supplier\u003c? extends T\u003e valueIfAbsent) throws CancellationException, CompletionException;\nT join() throws CancellationException, CompletionException;\n```\nSo it should be pretty straightforward to use the `Promise` as a drop-in replacement for the `CompletableFuture` in many cases.\n\nAlthough the library is compatible with JDK 1.8 there are methods in `Promise` interface that makes it \"upfront compatible\" with the higher JDK versions (available since version [0.8.2](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.8.2)):\n```java\nPromise\u003cT\u003e exceptionallyAsync(Function\u003cThrowable, ? extends T\u003e fn);\nPromise\u003cT\u003e exceptionallyAsync(Function\u003cThrowable, ? extends T\u003e fn, Executor executor);\nPromise\u003cT\u003e exceptionallyCompose(Function\u003cThrowable, ? extends CompletionStage\u003cT\u003e\u003e fn);\nPromise\u003cT\u003e exceptionallyComposeAsync(Function\u003cThrowable, ? extends CompletionStage\u003cT\u003e\u003e fn);\nPromise\u003cT\u003e exceptionallyComposeAsync(Function\u003cThrowable, ? extends CompletionStage\u003cT\u003e\u003e fn, \n                                     Executor executor);\n```\n\nPlus, there are several overloads of the filtering operator that complements canonical `map/flatMap` (or `thenApply/thenCompose` in terms of the `CompletionStage` API), available since version [0.9.0](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.9.1):\n```java\nPromise\u003cT\u003e thenFilter(Predicate\u003c? super T\u003e predicate);\nPromise\u003cT\u003e thenFilter(Predicate\u003c? super T\u003e predicate, Function\u003c? super T, Throwable\u003e errorSupplier);\nPromise\u003cT\u003e thenFilterAsync(Predicate\u003c? super T\u003e predicate);\nPromise\u003cT\u003e thenFilterAsync(Predicate\u003c? super T\u003e predicate, Function\u003c? super T, Throwable\u003e errorSupplier);\nPromise\u003cT\u003e thenFilterAsync(Predicate\u003c? super T\u003e predicate, Executor executor);\nPromise\u003cT\u003e thenFilterAsync(Predicate\u003c? super T\u003e predicate, Function\u003c? super T, Throwable\u003e errorSupplier,\n                           Executor executor);\n```\n\nBesides this, there are numerous operators in the `Promise` API to work with timeouts and delays, to override default asynchronous executor and similar. All of them will be discussed later.\n\nWhen discussing `Promise` interface, it's mandatory to mention the accompanying class `Promises` that provides several useful methods to adapt third-party `CompletionStage` (including the standard `CompletableFuture`) to the `Promise` API. First, there are two unit operations to create successfully/faulty settled `Promise`-es: \n```java\npublic final class Promises {\n  ...\n  static \u003cT\u003e Promise\u003cT\u003e success(T value)\n  static \u003cT\u003e Promise\u003cT\u003e failure(Throwable exception)\n  ...\n}\n```\nActually, release [0.9.0](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.9.0) adds the third unit operation:\n```java\npublic final class Promises {\n  ...\n  static \u003cT\u003e Promise\u003cT\u003e maybe(Optional\u003cT\u003e maybeValue)\n  ....\n}\n```\nIt converts the `Optional` supplied either to the successfully settled `Promise` or to the faulty settled one with [NoSuchElementException](https://docs.oracle.com/javase/8/docs/api/java/util//NoSuchElementException.html).\n\nSecond, there is an adapter method `from`:\n```java\npublic final class Promises {\n  ...\n  static \u003cT\u003e Promise\u003cT\u003e from(CompletionStage\u003cT\u003e stage)\n  ...\n}\n```\nIt behaves as the following: \n1. If the supplied `stage` is already a `Promise` then it is returned unchanged\n2. If `stage` is a `CompletableFuture` then a specially-tailored wrapper is returned.\n3. If `stage` additionally implements `Future` then specialized wrapper is returned that delegates all the blocking methods defined in `Future` API\n4. Otherwise generic wrapper is created with good-enough implementation of blocking `Future` API atop of asynchronous `CompletionStage` API.\n\nTo summarize, the returned wrapper delegates as much as possible functionality to the supplied `stage` and _never_ resorts to [CompletionStage.toCompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html#toCompletableFuture--) because in Java 8 API it's an optional method. From documentation: \"A CompletionStage implementation that does not choose to interoperate with others may throw UnsupportedOperationException.\" (this text was dropped in Java 9+). In general, Tascalate Concurrent library does not depend on this method and should be interoperable with any minimal (but valid) `CompletionStage` implementation.\n\nIt's important to emphasize, that `Promise`-s returned from `Promises.success`, `Promises.failure` and `Promises.from` methods are cancellable in the same way as `CompletableFuture`, but are not interruptible in general, while interruption depends on a concrete implementation. Next we discuss the concrete implementation of an interruptible `Promise` provided by the Tascalate Concurrent library -- the `CompletableTask` class.\n\n## 2. CompletableTask\nThis is why this project was ever started. `CompletableTask` is the implementation of the `Promise` API for long-running blocking tasks.\nTypically, to create a `CompletableTask`, you should submit [Supplier](https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html) / [Runnable](https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html) to the [Executor](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html) right away, in a similar way as with [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html):\n\n```java\nPromise\u003cSomeValue\u003e p1 = CompletableTask.supplyAsync(() -\u003e {\n  return blockingCalculationOfSomeValue();\n}, myExecutor);\n\nPromise\u003cVoid\u003e p2 = CompletableTask.runAsync(this::someIoBoundMethod, myExecutor);\n```\n`blockingCalculationOfSomeValue` and `someIoBoundMethod` in the example above can have I/O code, work with blocking queues, do blocking get on regular Java-s `Future`-s and alike. If at later time you decide to cancel either of the returned promises then corresponding `blockingCalculationOfSomeValue` and `someIoBoundMethod` will be interrupted (if not completed yet).\n\nIn the realm of I/O-related functionality, failures like connection time-outs, missing or locked files are pretty common, and checked exceptions mechanism is used frequently to signal failures. Therefore the library provides an entry point to the API that accepts [Callable](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Callable.html) instead of `Supplier`:\n```java\n// Notice the checked exception in the method signature\nbyte[] loadFile(File file) throws IOException {\n    byte[] result = ... //load file content;\n    return result;\n}\n...\nExecutorService executorService = Executors.newFixedThreadPool(6);\nPromise\u003cbyte[]\u003e contentPromise = CompletableTask.submit(\n    () -\u003e loadFile(new File(\"./myfile.dat\")), \n    executorService\n); \n```\n\nAdditionally, there are 2 unit operations to create a `CompletableTask`:\n\na.\t`CompletableTask.asyncOn(Executor executor)`\nReturns an already-completed null-valued `Promise` that is \"bound\" to the specified executor. I.e. any function passed to asynchronous composition methods of `Promise` (like `thenApplyAsync` / `thenAcceptAsync` / `whenCompleteAsync` etc.) will be executed using this executor unless executor is overridden via explicit composition method parameter. Moreover, any nested composition calls will use same executor, if it’s not redefined via explicit composition method parameter:\n```java\nCompletableTask\n  .asyncOn(myExecutor)\n  .thenApplyAsync(myValueGenerator)\n  .thenAcceptAsync(myConsumer)\n  .thenRunAsync(myAction);\n```  \nAll of `myValueGenerator`, `myConsumer`, `myAction` will be executed using `myExecutor`.\n\nb.\t`CompletableTask.completed(T value, Executor executor)`\nSame as above, but the starting point is a `Promise` completed with the specified value:\n```java\nCompletableTask\n   .completed(\"Hello!\", myExecutor)\n   .thenApplyAsync(myMapper)\n   .thenApplyAsync(myTransformer)   \n   .thenAcceptAsync(myConsumer)\n   .thenRunAsync(myAction);\n```  \nAll of `myMapper`, `myTransformer`, `myConsumer`, `myAction` will be executed using `myExecutor`.\n**WARNING** Before release [0.9.0](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.9.0) this method was named `CompletableTask.complete(...)`\n\nCrucially, all composed promises support true cancellation (incl. interrupting thread) for the functions supplied as arguments:\n```java\nPromise\u003c?\u003e p1 = CompletableTask.asyncOn(myExecutor)\nPromise\u003c?\u003e p2 = p1.thenApplyAsync(myValueGenerator)\nPromise\u003c?\u003e p3 = p2.thenRunAsync(myAction);\n  \n...\np2.cancel(true);\n```  \nIn the example above `myValueGenerator` will be interrupted if already in progress. Both `p2` and `p3` will be settled with failure: `p2` with a [CancellationException](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CancellationException.html) and `p3` with a [CompletionException](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionException.html).\n\nYou may notice, that above the term \"asynchronous composition methods\" is used, as well as `*Async` calls in examples (like `thenApplyAsync`, `thenRunAsync`. This is not accidental: non-asynchronous methods of `CompletionStage` API are not interruptible. The grounding beneath the design decision is that invoking asynchronous methods involves inevitable overhead of putting command to the queue of the executor, starting new threads implicitly, etc. And for simple, non-blocking methods, like small calculations, trivial transformations and alike this overhead might outweigh method's execution time itself. So the guideline is: use asynchronous composition methods for heavy I/O-bound blocking tasks, and use non-asynchronous composition methods for (typically lightweight) calculations.\n\nWorth to mention, that `CompletableTask`-s and `Promise`-s composed out of it may be ever interruptible _only_ if the `Executor` used is interruptible by nature. For example, [ThreadPoolExecutor](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html) supports interruptible tasks, but [ForkJoinPool](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html) does not!\n\n## 3. DependentPromise\nAs it mentioned above, once you cancel `Promise`, all `Promise`-s that depends on this promise are completed with [CompletionException](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionException.html) wrapping [CancellationException](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CancellationException.html). This is a standard behavior, and [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) works just like this.\n\nHowever, when you cancel derived `Promise`, the original `Promise` is not cancelled: \n```java\nPromise\u003c?\u003e original = CompletableTask.supplyAsync(() -\u003e someIoBoundMethod(), myExecutor);\nPromise\u003c?\u003e derivedA = original.thenRunAsync(() -\u003e someMethodA() );\nPromise\u003c?\u003e derivedB = original.thenRunAsync(() -\u003e someMethodB() );\n...\nderivedB.cancel(true);\n```\nSo if you cancel `derivedB` above it's [Runnable](https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html) method, wrapping `someMethod`, is interrupted. However the `original` promise is not cancelled and `someIoBoundMethod` keeps running. Also, `derivedA` is not cancelled, and such behavior is expected. However, sometimes we have a linear chain of the promises and have a requirement to cancel the whole chain from a tail to the head. Consider the following method:\n\n```java\npublic Promise\u003cDataStructure\u003e loadData(String url) {\n   return CompletableTask.supplyAsync( () -\u003e loadXml(url) ).thenApplyAsync( xml -\u003e parseXml(xml) ); \n}\n\n...\nPromise\u003cDataStructure\u003e p = loadData(\"http://someserver.com/rest/ds\");\n...\nif (someCondition()) {\n  // Only second promise is canceled, parseXml.\n  p.cancel(true);\n}\n```\n\nClients of this method see only derived promise, and once they decide to cancel it, it is expected that any of `loadXml` and `parseXml` will be interrupted if not completed yet. To address this issue the library provides [DependentPromise](https://github.com/vsilaev/tascalate-concurrent/blob/master/src/main/java/net/tascalate/concurrent/DependentPromise.java) class:\n```java\npublic Promise\u003cDataStructure\u003e loadData(String url) {\n   return DependentPromise\n          .from(CompletableTask.supplyAsync( () -\u003e loadXml(url) ))\n          .thenApplyAsync( xml -\u003e parseXml(xml), true ); \n}\n\n...\nPromise\u003cDataStructure\u003e p = loadData(\"http://someserver.com/rest/ds\");\n...\nif (someCondition()) {\n  // Now the whole chain is canceled.\n  p.cancel(true);\n}\n```\n[DependentPromise](https://github.com/vsilaev/tascalate-concurrent/blob/master/src/main/java/net/tascalate/concurrent/DependentPromise.java) overloads methods like `thenApply` / `thenRun` / `thenAccept` / `thenCombine` etc with additional argument:\n- if method accepts no other [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html), like `thenApply` / `thenRun` / `thenAccept` etc, then it's a boolean flag `enlistOrigin` to specify whether or not the original `Promise` should be enlisted for the cancellation.\n- if method accepts other [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html), like `thenCombine` / `applyToEither` / `thenAcceptBoth` etc, then it's a set of [PromiseOrigin](https://github.com/vsilaev/tascalate-concurrent/blob/master/src/main/java/net/tascalate/concurrent/PromiseOrigin.java) enum values, that specifies whether or not the original `Promise` and/or a `CompletionStage` supplied as argument should be enlisted for the cancellation along with the resulting promise, for example:\n\n```java\npublic Promise\u003cDataStructure\u003e loadData(String url) {\n   return DependentPromise\n          .from(CompletableTask.supplyAsync( () -\u003e loadXml(url + \"/source1\") ))\n          .thenCombine( \n              CompletableTask.supplyAsync( () -\u003e loadXml(url + \"/source2\") ), \n              (xml1, xml2) -\u003e Arrays.asList(xml1, xml2),\n              PromiseOrigin.ALL\n          )          .\n          .thenApplyAsync( xmls -\u003e parseXmlsList(xmls), true ); \n}\n```\n\nPlease note, then in release 0.5.4 there is a new default method `dependent` in interface [Promise](https://github.com/vsilaev/tascalate-concurrent/blob/master/src/main/java/net/tascalate/concurrent/Promise.java) that serves the same purpose and allows to write chained calls:\n\n```java\npublic Promise\u003cDataStructure\u003e loadData(String url) {\n   return CompletableTask\n          .supplyAsync( () -\u003e loadXml(url) )\n          .dependent()\n          .thenApplyAsync( xml -\u003e parseXml(xml), true ); \n}\n```\n\nAttention: just calling `dependent()` on the `Promise` is not enough to change the behavior of the \"default\" `thenApply` / `thenRun` / `thenAccept` / `thenCombine` etc methods defined in `CompletionStage` - you have to use overloaded form with either `boolean` or `Set\u003cPromiseOrigin\u003e` last parameter _explicitly_. This is the intentional design decision: just recall, that the `Promise` returned in the example above can be used by the client code to create _independent_ promises (as per `CompletionStage` API), so the library has to follow the rule of the least surprise.\n\nBelow are 2 examples (wrong and right) to re-iterate the statement above in Java code.\n\nWrong code to cancel the whole chain:\n```java\nPromise\u003cXml\u003e xml = CompletableTask.supplyAsync( () -\u003e loadXml(url) )\nPromise\u003cData\u003e data = xml.dependent()\n                        .thenApplyAsync( xml -\u003e parseXml(xml) );  // Not overloaded method - \n                                                                  // no \"true\" as the last parameter\n...\n// This cancels only \"data\" promise, but will not cancel \"xml\" promise\ndata.cancel(true);\n```\nRight code to cancel the whole chain:\n```java\nPromise\u003cXml\u003e xml = CompletableTask.supplyAsync( () -\u003e loadXml(url) )\nPromise\u003cData\u003e data = xml.dependent()\n                        .thenApplyAsync( xml -\u003e parseXml(xml), true );  // Overloaded method - \n                                                                        // \"true\" as last parameter means \n                                                                        // enlist \"origin\" promise \n                                                                        // for cancellation\n...\n// This cancels both \"data\" promise AND the \"xml\" promise (if it's not completed yet)\ndata.cancel(true);\n```\n\nSo far so good. And following `CompletionStage` API contract is good, no doubt. But what if you have to create locally a chain of 10 stages? 30 stages? It's both pretty boring and error-prone to put additional parameters to enforce overloaded method(s) usage. And error-prone means just this -- it's pretty easy to forget to type \"true\" as the latest parameter and break the cancellation chain. Tascalate Concurrent provides an option to handle this edge case: use overloaded form of `dependent()` method - `dependent(Set\u003cPromiseOrigin\u003e)`. Here is an example from the real-life issue raised in the real-life project:\n```java\nPromise\u003c?\u003e myPromise = \nCompletableTask.supplyAsync(() -\u003e candidate, pool)\n               .dependent(PromiseOrigin.ALL) //Key point - alter the behavior of CompletionStage API methds\n               .thenApplyAsync(CheckIp::doWork)\n               .thenApplyAsync(CheckType::doWork)\n               .thenApplyAsync(CheckExclusion::doWork)\n               .thenApplyAsync(AssignEntity::doWork)\n               .thenCombineAsync(collectedStatsPromise, this:combineWithStats) // \u003c-- pay attention here\n               .thenApplyAsync(DecideWmi::doWork)\n               .thenApplyAsync(ObtainWmiConnection::doWork)\n               .thenApplyAsync(ObtainRegistryWmiConnection::doWork)\n               .thenApplyAsync(RunCompliance::doWork)\n               .thenApplyAsync(DecideComplianceResult::doWork)\n               .thenApplyAsync(CreateAlert::doWork)\n               .thenApplyAsync(ApplyFailureManager::doWork)\n               .thenApplyAsync(ApplyDisconnectManager::doWork)\n               .thenApplyAsync(EnforceCompliance::doWork)\n               .exceptionally(ExceptionHandlerService::handle);\n```\nUnlike the conservative form of the `dependent()` decorator, the overloaded `dependent(PromiseOrigin.ALL)` will enlist ALL the promises mentioned by composition methods as _dependent_ and will cancel them when `myPromise` is cancelled. Even the `collectedStatsPromise` that is passed from outside! Everything enlisted will form a single block of cancellation. By the way, if you don't need to cancel `collectedStatsPromise` above use `dependent(PromiseOrigin.THIS_ONLY)` decorator - it doesn't enlist \"side-passed\" promises.\n\nWell, but what about obeying `CompletionStage` contract? Is it still safe to return `myPromise` to clients that are unaware of its overwritten behavior? It's not. You should revert the effect of the `dependent(PromiseOrigin.ALL)` decorator before passing `myPromise` outside:\n```java\npublic Promise\u003c?\u003e forkWmiProcessingChain(Promise\u003cStats collectedStatsPromise) {\n  Promise\u003c?\u003e myPromise = \n  CompletableTask.supplyAsync(() -\u003e candidate, pool)\n                 .dependent(PromiseOrigin.ALL) \n                 .thenApplyAsync(CheckIp::doWork)\n                 .thenApplyAsync(CheckType::doWork)\n                 ...\n                 .exceptionally(ExceptionHandlerService::handle);\n  return myPromise.unwrap(); // or myPromise.raw() in this case               \n}\n```\n\nThe final operator in the function above - `unwrap()` removes the latest decorator applied, the `dependent(...)`. Looking ahead, I should mention that `raw()` will remove _all_ the decorators applied. Yes, there are several possible - and the `dependent(...)` is just one of them. In the next chapters we discuss `defaultAsyncOn` decorator and later you will see custom decorators (the ones not directly bound to the `Promise` API as methods).\n\n## 4. Wait! Wait! It's not cancellable!!!\nOne of the most common complains in the issue tracker of Tascalate Concurrent project is a variation of the report \"code is not cancelled when requested\". The symptoms are typical: `Promise` is cancelled, any dependent `Promise`-s are completed exceptionally (as expected) but threads keep running till the end of the code submitted to an executor. So the primary promise of the library is broken: execution is not interrupted.\n\nIs library broken? No. Is user code correct? Well, yes. But library code and user code do not cooperate well to really cancel asynchronous execution.\n\nThe promise returned from `CompletableTask` methods like `supplyAsync` / `runAsync` as well as any derived `Promise` (via `thenApply` or `thenRun`) does the following two things:\n1. Set own state to _cancelled_ and let transitions to any dependent promises run (same as `CompletableFuture`)\n2. Interrupt the current `Thread` via `Thread.currentThread().interrupt()` (unlike `CompletableFuture`)\n\nAnd it's responsibility of the user code - all of these `Runnable`, `Consumer\u003cT\u003e` and `Function\u003cT,R\u003e` passed - to react on the `Thread.currentThread().isInterrupted()` flag. Let us consider typical scenarios.\n1. User code is a computational code and do not use I/O.\n\nIn this case you have to put explicit checks for `Thread.currentThread().isInterrupted()` to break execution via either breaking loops, early returns or throwing exception:\n\n```java\nouter:\nfor (int i = 0; i \u003c SOME_LARGE_SIZE; i++) {\n  for (int j = 0; j \u003c SOME_EVEN_LARGER_SIZE; j++) {\n    if (Thread.currentThread().isInterrupted()) {\n      break outer;\n    }\n    // some calcs here\n  }\n}\n```\n\nIt's up to library user to select how often to check the flag: there are always trade-offs between overhead for regular execution time (when execution is not cancelled) and the delay before thread react on cancellation. In the example above the check may be moved from the inner loop to the outer loop - this will speed-up normal execution path but the code will react on the cancellation with delay.\n\nSome API provides good built-in points to check for early exit, the good example is [java.nio.file.FileVisitor](https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileVisitor.html) + [java.nio.file.Files walkFileTree](https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#walkFileTree(java.nio.file.Path,%20java.nio.file.FileVisitor)). Here you can just put checks in `previsitDirectory` / `visitFile`:\n\n```java\n@Test\n@SuppressWarnings(\"unchecked\")\npublic void testReallife() throws Exception {\n  ElapsedTime time = new ElapsedTime();\n  Executor executor = Executors.getDefaultExecutor();\n  Promise\u003cVoid\u003e promise = CompletableTask.runAsync(() -\u003e {\n    try {\n      Files.walkFileTree(Paths.get(\"d:/\"), new FileVisitor\u003c\u003e() {\n        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\n          System.out.printf(\"[%d ms] [%s] Task#%d: visiting dir %s%n\", \n                            time.current(), Thread.currentThread(), id, dir);\n          if (Thread.currentThread().isInterrupted()) {\n            // STOP when interrupted\n            return FileVisitResult.TERMINATE;\n          } else {\n            return FileVisitResult.CONTINUE;\n          }\n        }\n\n      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {...}\n      public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {...}\n      public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {...}\n  }, executor);\n  Thread.sleep(3000);\n  System.out.printf(\"[%d ms] canceling%n\", time.current());\n  promise.cancel(true);\n  assertCanceled(promise);\n}\n```\n\n2. You are using old blocking API of `java.io.InputStream` or `java.net.URLConnection`\nProbably, your code uses old blocking streams from `java.io` like `java.io.FileInputStream` or `SocketInputStream` opened from `java.net.Socket`. Or you are using `java.net.URLConnection`. Or outdated blocking Apache HTTP Client. These all prevents running thread from termination once interrupted -- all of these API-s are blocking and do not react on interruptions. The options are:\n- If you are using some third-party synchronous networking library then try to replace it with the asynchronous version. For HTTP protocol there is a plenty of options like AsyncHttpClient and OkHttp. Both returns `CompletableFuture` as operation results and therefore could be easily plugged with the rest of Tascalate Concurrent code.\n- If you are using blocking file API try to replace it with NIO version, it's the best option:\n\n```java\ntry (InputStream in = new FileInputStream(\"E:/Downloads/LargeFile.rar\")) {\n... // Work with input stream\n}\n\n==\u003e\nimport java.nio.channels.Channels;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\n...\ntry (InputStream in = \n  Channels.newInputStream(FileChannel.open(Paths.get(\"E:/Downloads/LargeFile.rar\"), \n                                           StandardOpenOption.READ)))) {\n... // Work with input stream\n} \n// Same could be done for sockets\n```\n- If don't like to use new NIO API, but sources with blocking IO may be altered, then `BlockingIO` class provided by Tascalate Concurrent can help:\n\n```java\nPromise\u003c?\u003e promise = CompletableTask.supplyAsync(\n  BlockingIO.interruptible( // Wrap Supplier into interruptible Supplier\n    () -\u003e {\n      // Register InputStream after creation as interruption target\n      try (InputStream in = BlockingIO.register(new FileInputStream(\"E:/Downloads/LargeFile.rar\"))) {\n        ... // Work with input stream\n      } catch (IOException ex) {\n        throw new RuntimeException(ex);\n      } \n    }\n  )\n);\n...\npromise.cancel(true);\n```\n`BlockingIO.interruptible(...)` can wrap as interruptible all the functional interfaces used in `CompletionStage` / `Promise` API. The parameter to the `BlockingIO.register` should be any implementation of `java.lang.Closeable` that will be closed on thread interruption. For `InputStream` or `OutputStream` it is just the stream itself. For `java.net.HttpUrlConnection` you can use\n\n```java\nHttpURLConnection conn = (HttpURLConnection)(new URL(url).openConnection());\nBlockingIO.register(conn::disconnect);\n```\n\n`BlockingIO` is a late addition to the Tascalate Concurrent, it's available only since version [0.9.5](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.9.5).\n\nUnfortunately, it's necessary to put this statement straight at the end: if the blocking API is hidden behind third-party library code (like Spring RestTemplate) then you are out of luck - Tascalate Concurrent will not support true interruptions in this scenario. \n\n## 5. Overriding default asynchronous executor\nOne of the pitfalls of the `CompletableFuture` implementation is how it works with default asynchronous executor. Consider the following example:\n```java\nCompletionStage\u003cString\u003e p1 = CompletableFuture.supplyAsync(this::produceValue, executorInitial);\nCompletionStage\u003cString\u003e p2 = p1.thenApplyAsync(this::transformValueA);\nCompletionStage\u003cString\u003e p3 = p2.thenApplyAsync(this::transformValueB, executorNext);\nCompletionStage\u003cString\u003e p4 = p3.thenApplyAsync(this::transformValueC);\n```\nThe call to `produceValue` will be executed on the `executorInitial` - it is passed explicitly. However, the call to `transformValueA` will be excuted on... `ForkJoinPool.commonPool()`! Hmmmm... Probably this makes sense, but how to force using alternative executor by default? No way! Probably this is possible with deeper calls? The answer is \"NO\" again! The invocation to `transformValueB` ran on explicitly supplied `executorNext`. But next call, `transformValueC` will be executed on... you guess it... `ForkJoinPool.commonPool()`!\n\nSo, once you use `CompletableFuture` with JEE environment you must pass explicit instance of [ManagedExecutorService](https://docs.oracle.com/javaee/7/api/javax/enterprise/concurrent/ManagedExecutorService.html) to each and every method call. Not very convenient! To be fair, with Java 9+ API you can redefine this behavior via sub-classing `CompletableFuture` and overriding two methods: [defaultExecutor](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/CompletableFuture.html#defaultExecutor--) and [newIncompleteFuture](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/CompletableFuture.html#newIncompleteFuture--). Plus, you will have to define your own \"entry points\" instead of the standard `CompletableFuture.runAsync` and `CompletableFuture.supplyAsync`. \n\nWith `CompletableTask` the situation is just the opposite. Let us rewrite the example above:\n```java\nCompletionStage\u003cString\u003e p1 = CompletableTask.supplyAsync(this::produceValue, executorInitial);\nCompletionStage\u003cString\u003e p2 = p1.thenApplyAsync(this::transformValueA);\nCompletionStage\u003cString\u003e p3 = p2.thenApplyAsync(this::transformValueB, executorNext);\nCompletionStage\u003cString\u003e p4 = p3.thenApplyAsync(this::transformValueC);\n```\nThe call to `produceValue` will be executed on the `executorInitial`, obviously. But now, the call to `transformValueA` will be executed also on `executorInitial`! What's about deeper calls? The invocation to `transformValueB` ran on explicitly supplied `executorNext`. And next call, `transformValueC` will be executed on... check your intuition... `executorNext`. The logic behinds this is the following: the latest explicitly specified `Executor` is what will be used for all nested asynchronous composition methods without an explicit `Executor` parameter.\n\nObviously, it's rarely the case when one size fits all. Since release [0.6.6](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.6.6) there are two new options to specify default asynchronous executor:\n1. `CompletableTask` has an overloaded method:\n```java\npublic static Promise\u003cVoid\u003e asyncOn(Executor executor, boolean enforceDefaultAsync)\n```\nWhen `enforceDefaultAsync` is `true` then all nested asynchronous composition methods without explicit `Executor` parameter will use the provided executor, even if previous composition methods use alternative `Executor`. This is somewhat similar to `CompletableFuture` but with the ability to explicitly set the default asynchronous executor initially.\n\n2. `Promise` interface has the following operation:\n```java\nPromise\u003cT\u003e defaultAsyncOn(Executor executor)\n```\nThe returned decorator will use the specified executor for all nested asynchronous composition methods without explicit `Executor` parameter. So, at any point, you are able to switch to the desired default asynchronous executor and keep using it for all nested composition call.\n\nTo summarize, with Tascalate Concurrent you have the following options to control what is the default asynchronous executor:\n1. The latest explicit `Executor` passed to `*Async` method is used for derived `Promise`-s - the default option.\n2. Single default `Executor` passed to the root `CompletableTask.asyncOn(Executor executor, true)` call is propagated through the whole chain. This is the only variant supported with `CompletableFuture` in Java 9+, though, with custom coding.\n3. Redefine `Executor` with `defaultAsyncOn(Executor executor)` for all derived `Promise`-s.\nHaving the best of three(!) worlds, the only responsibility of the library user is to use these options consistently! \n\nThe last thing that should be mentioned is a typical task when you would like to start interruptible blocking method after completion of the standard `CompletableFuture`. The following utility method is defined in the `CompletableTask`:\n```java\npublic static \u003cT\u003e Promise\u003cT\u003e waitFor(CompletionStage\u003cT\u003e stage, Executor executor)\n```\nRoughly, this is a shortcut for the following:\n```java\nCompletableTask.asyncOn(executor).thenCombine(stage, (u, v) -\u003e v);\n```\nA typical usage of this method is:\n```java\nTaskExecutorService executorService = TaskExecutors.newFixedThreadPool(3);\nCompletableFuture\u003cString\u003e replyUrlPromise = sendRequestAsync();\nPromise\u003cbyte[]\u003e dataPromise = CompletableTask.waitFor(replyUrlPromise, executorService)\n    .thenApplyAsync(url -\u003e loadDataInterruptibly(url));\n```\nThe `dataPromise` returned may be cancelled later and `loadDataInterruptibly` will be interrupted if not completed by that time.\n\n## 6. Timeouts\nAny robust application requires certain level of functionality, that handles situations when things go wrong. An ability to cancel a hanged operation existed in the library from the day one, but, obviously, it is not enough. Cancellation per se defines \"what\" to do in face of the problem, but the responsibility \"when\" to do was left to an application code. Starting from release [0.5.4](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.5.4) the library fills the gap in this functionality with timeout-related stuff.\n\nAn application developer now has the following options to control execution time of the `Promise` (declared in `Promise` interface itself):\n```java\n\u003cT\u003e Promise\u003cT\u003e orTimeout(long timeout, TimeUnit unit[, boolean cancelOnTimeout = true])\n\u003cT\u003e Promise\u003cT\u003e orTimeout(Duration duration[, boolean cancelOnTimeout = true])\n```\nThese methods creates a new `Promise` that is either settled successfully/exceptionally when original promise is completed within a timeout given; or it is settled exceptionally with a [TimeoutException](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/TimeoutException.html) when time expired. In any case, handling code is executed on the default asynchronous [Executor](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html) of the original `Promise`.\n```java\nExecutor myExecutor = ...; // Get an executor\nPromise\u003cString\u003e callPromise = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningIoBoundMehtod(), myExecutor )\n    .orTimeout( Duration.ofSeconds(3) );\n    \nPromise\u003c?\u003e nextPromiseSync = callPromise.whenComplete((v, e) -\u003e processResultSync(v, e));\nPromise\u003c?\u003e nextPromiseAsync = callPromise.whenCompleteAsync((v,e) -\u003e processResultAsync(v, e));\n```\nIn the example above `callPromise` will be settled within 3 seconds either successfully/exceptionally as a result of the `someLongRunningIoBoundMehtod` execution, or exceptionally with a `TimeoutException`.\n\nIt's worth to mention, that _both_ `processResultSync` and `processResultAsync` will be executed with `myExecutor`, if timeout is triggered - this rule is true for all timeout-related methods.\n\nThe optional `cancelOnTimeout` parameter defines whether or not to cancel the original `Promise` when time is expired; it is implicitly true when omitted. So in example above `the someLongRunningIoBoundMehtod` will be interrupted if it takes more than 3 seconds to complete. Pay attention: any `Promise` is cancellable on timeout, even wrappers created via `Promises.from(stage)`, but only `CompletableTask` is interruptible!\n\nCancelling original promise on timeout is a desired behavior in most cases but not always. In reality, \"Warn-first-Cancel-next\"  scenarios are not rare, where \"warn\" may be logging, sending notification emails, showing messages to user on UI etc. The library provides an option to set several non-cancelling timeouts like in the example below:\n```java\nExecutor myExecutor = ...; // Get an executor\nPromise\u003cString\u003e resultPromise = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningIoBoundMehtod(), executor );\n\n// Show UI message to user to let him/her know that everything is under control\nPromise\u003c?\u003e t1 = resultPromise\n    .orTimeout( Duration.ofSeconds(2), false )\n    .exceptionally( e -\u003e {\n      if (e instanceof TimeoutException) {\n        UI.showMessage(\"The operation takes longer than expected, please wait...\");\n      }\n      return null;\n    }, false); \n\n// Show UI confirmation to user to let him/her cancel operation explicitly\nPromise\u003c?\u003e t2 = resultPromise\n    .orTimeout( Duration.ofSeconds(5), false )\n    .exceptionally( e -\u003e {\n      if (e instanceof TimeoutException) {\n        UI.clearMessages();\n        UI.showConfirmation(\"Service does not respond. Do you whant to cancel (Y/N)?\");\n      }\n      return null;\n    }, false); \n\n// Cancel in 10 seconds\nresultPromise.orTimeout( Duration.ofSeconds(10), true );\n```\nPlease note that the timeout is started from the call to the `orTimeout` method. Hence, if you have a chain of unresolved promises ending with the `orTimeout` call then the whole chain should be completed within the time given:\n```java\nExecutor myExecutor = ...; // Get an executor\nPromise\u003cString\u003e parallelPromise = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningDbCall(), executor );\nPromise\u003cList\u003cString\u003e\u003e resultPromise = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningIoBoundMehtod(), executor )\n    .thenApplyAsync( v -\u003e converterMethod(v) )\n    .thenCombineAsync(parallelPromise, (u, v) -\u003e Arrays.asList(u, v))\n    .orTimeout( Duration.ofSeconds(5) );\n```\nIn the latest example `resultPromise` will be resolved successfully if and only if all of `someLongRunningIoBoundMehtod`, `converterMethod` and even `someLongRunningDbCall` are completed within 5 seconds. If it's necessary to restrict execution time of the single step, please use standard `CompletionStage.thenCompose` method. Say, that in the previous example we have to restrict execution time of the `converterMethod` only. Then the modified chain will look like:\n```java\nPromise\u003cList\u003cString\u003e\u003e resultPromise = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningIoBoundMehtod(), executor )\n    // Restict only execution time of converterMethod\n    // -- start of changes\n    .thenCompose( v -\u003e \n        CompletableTask.completed(v, executor)\n                       .thenApplyAsync(vv -\u003e converterMethod(vv))\n                       .orTimeout( Duration.ofSeconds(5) )\n    )\n    // -- end of changes\n    .thenCombineAsync(parallelPromise, (u, v) -\u003e Arrays.asList(u, v))\n    ;\n```\n\nMoreover, in the _original_ example only the call to the `thenCombineAsync` will be cancelled on timeout (the last in the chain), to cancel the whole chain please use the functionality of the `DependentPromise` interface (will be discussed later):\n```java\nExecutor myExecutor = ...; // Get an executor\nPromise\u003cString\u003e parallelPromise = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningDbCall(), executor );\nPromise\u003cList\u003cString\u003e\u003e resultPromise = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningIoBoundMehtod(), executor )\n    .dependent()\n    // enlist promise of someLongRunningIoBoundMehtod for cancellation\n    .thenApplyAsync( v -\u003e converterMethod(), true )  \n    // enlist result of thenApplyAsync and parallelPromise for cancellation\n    .thenCombineAsync(parallelPromise, (u, v) -\u003e Arrays.asList(u, v), PromiseOrigin.ALL)\n    .orTimeout( Duration.ofSeconds(5) ); // now timeout will cancel the whole chain\n```\n\nAnother useful timeout-related methods declared in `Promise` interface are:\n```java\n\u003cT\u003e Promise\u003cT\u003e onTimeout(T value, long timeout, TimeUnit unit[, boolean cancelOnTimeout = true])\n\u003cT\u003e Promise\u003cT\u003e onTimeout(T value, Duration duration[, boolean cancelOnTimeout = true])\n\u003cT\u003e Promise\u003cT\u003e onTimeout(Supplier\u003c? extends T\u003e, long timeout, TimeUnit unit[, boolean cancelOnTimeout = true])\n\u003cT\u003e Promise\u003cT\u003e onTimeout(Supplier\u003c? extends T\u003e, Duration duration[, boolean cancelOnTimeout = true])\n```\nThe `onTimeout` family of methods are similar in all regards to the `orTimeout` methods with the single obvious difference - instead of completing resulting `Promise` exceptionally with the `TimeoutException` when time is expired, they are settled successfully with the alternative `value` supplied (either directly or via [Supplier](https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html)):\n```java\nExecutor myExecutor = ...; // Get an executor\nPromise\u003cString\u003e callPromise = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningIoBoundMehtod(), executor )\n    .onTimeout( \"Timed-out!\", Duration.ofSeconds(3) );\n```\nThe example shows, that `callPromise` will be settled within 3 seconds either successfully/exceptionally as a result of the `someLongRunningIoBoundMehtod` execution, or with a default value `\"Timed-out!\"` when time exceeded.\n\nIt's important to mention the crucial difference between `Promise.orTimeot / onTimeout` and `CompletableFuture.orTimeout / completeOnTimeout` in Java 9+. In Tascalate Concurrent both operations return a _new_ `Promise`, that is may be canceled individually, without cancelling the original `Promise`. Moreover, the original `Promise` will not be completed with `TimeoutException` when time expired but rather with the `CancellationException` (in the case of `orTimeout([duration], true)` or `orTimeout([duration])`). The behavior of `CompletableFuture` in Java 9+ is radically different: timeout-related operations are just \"side-effects\", and the returned value is the original `CompletableFuture` itself. So the call to `completableFuture.orTimeout(100, TimeUnit.MILLIS).cancel()` will cancel the `completableFuture` itself, and there is no way to revert the timeout once it's set. Correspondingly, when time expired the original `completableFuture` will be completed exceptionally with `TimeoutException`.\n\nFinally, the `Promise` interface provides an option to insert delays into the call chain:\n```java\n\u003cT\u003e Promise\u003cT\u003e delay(long timeout, TimeUnit unit[, boolean delayOnError = true])\n\u003cT\u003e Promise\u003cT\u003e delay(Duration duration[, boolean delayOnError = true])\n```\nThe delay is started only after the original `Promise` is completed either successfully or exceptionally (unlike `orTimeout` / `onTimeout` methods where timeout is started immediately). The resulting delay `Promise` is resolved after the timeout specified with the same result as the original `Promise`. The latest methods' argument - `delayOnError` - specifies whether or not we should delay if original Promise is resolved exceptionally, by default this argument is `true`. If `false`, then delay `Promise` is completed immediately after the failed original `Promise`. \n```java\nExecutor myExecutor = ...; // Get an executor\nPromise\u003cString\u003e callPromise1 = CompletableTask\n    .supplyAsync( () -\u003e someLongRunningIoBoundMehtod(), executor )\n    .delay( Duration.ofSeconds(1) ) // Give a second for CPU to calm down :)\n    .thenApply(v -\u003e convertValue(v));\n    \nPromise\u003cString\u003e callPromise2 = CompletableTask\n    .supplyAsync( () -\u003e aletrnativeLongRunningIoBoundMehtod(), executor )\n    .delay( Duration.ofSeconds(1), false ) // Give a second for CPU to calm down ONLY on success :)\n    .thenApply(v -\u003e convertValue(v));\n```\nLike with other timeout-related methods, `convertValue` is invoked on the default asynchronous `Executor` of the original `Promise`.  \n\nYou may notice, that delay may be introduced only in the middle of the chain, but what to do if you'd like to back-off the whole chain execution? Just start with a resolved promise!\n```java\n// Option 1\n// Interruptible tasks chain on the executor supplied\nCompletableTask.asyncOn(executor)\n    .delay( Duration.ofSeconds(5) )\n    .thenApplyAsync(ignore -\u003e produceValue());\n\n// Option2\n// Computational tasks on ForkJoinPool.commonPool()\nPromises.from(CompletableFuture.completedFuture(\"\"))\n    .delay( Duration.ofSeconds(5) )\n    .thenApplyAsync(ignore -\u003e produceValue());\n```\nAs long as back-off execution is not a very rare case, the library provides the following convenient shortcuts in the `CompletableTask` class:\n```java\nstatic Promise\u003cDuration\u003e delay(long timeout, TimeUnit unit, Executor executor);\nstatic Promise\u003cDuration\u003e delay(Duration duration, Executor executor);\n```\nNotice, that in Java 9+ a different approach is chosen to implement delays - there is no corresponding operation defined for the `CompletableFuture` object and you should use delayed `Executor`. Please read documentation on the [CompletableFuture.delayedExecutor](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/CompletableFuture.html#delayedExecutor-long-java.util.concurrent.TimeUnit-java.util.concurrent.Executor-) method for details.\n\n## 7. Combining several CompletionStage-s.\nThe utility class `Promises` provides a rich set of methods to combine several `CompletionStage`-s, that lefts limited functionality of `CompletableFuter.allOf / anyOf` far behind:\n1. The library works with any `CompletionStage` implementation without resorting to converting arguments to `CompletableFuture` first (and `CompletionStage.toCompletableFuture` is an optional operation, at least it's documented so in Java 8).\n2. It's possible to pass either an array or a `List` of `CompletionStage`-s as arguments.\n3. The resulting `Promise` let access individual results of the settled `CompletionStage`-s passed.\n4. There is an option to cancel non-settled `CompletionStage`-s passed once the result of the operation is known.\n5. Optionally you can specify whether or not to tolerate individual failures as long as they don't affect the final result.\n6. General _M completed successfully out of N passed promises_ scenario is possible.\n\nLet us review the relevant methods, from the simplest ones to the most advance.\n\n```java\nstatic \u003cT\u003e Promise\u003cList\u003cT\u003e\u003e all([boolean cancelRemaining=true,] CompletionStage\u003c? extends T\u003e... promises)\nstatic \u003cT\u003e Promise\u003cList\u003cT\u003e\u003e all([boolean cancelRemaining=true,] \n                                List\u003c? extends CompletionStage\u003c? extends T\u003e\u003e promises)\n````\nReturns a promise that is completed normally when all `CompletionStage`-s passed as parameters are completed normally; if any promise completed exceptionally, then resulting promise is completed exceptionally as well.\n\n```java\nstatic \u003cT\u003e Promise\u003cT\u003e any([boolean cancelRemaining=true,] CompletionStage\u003c? extends T\u003e... promises)\nstatic \u003cT\u003e Promise\u003cT\u003e any([boolean cancelRemaining=true,] \n                          List\u003c? extends CompletionStage\u003c? extends T\u003e\u003e promises)\n```\nReturns a promise that is completed normally when any `CompletionStage` passed as parameters is completed normally (race is possible); if all promises completed exceptionally, then resulting promise is completed exceptionally as well.\n\n```java\nstatic \u003cT\u003e Promise\u003cT\u003e anyStrict([boolean cancelRemaining=true,] CompletionStage\u003c? extends T\u003e... promises)\nstatic \u003cT\u003e Promise\u003cT\u003e anyStrict([boolean cancelRemaining=true,] \n                                List\u003c? extends CompletionStage\u003c? extends T\u003e\u003e promises)\n```\nReturns a promise that is completed normally when any `CompletionStage` passed as parameters is completed normally (race is possible); if any promise completed exceptionally before the first result is available, then resulting promise is completed exceptionally as well (unlike non-Strict variant, where exceptions are ignored if any result is available at all).\n\n```java\nstatic \u003cT\u003e Promise\u003cList\u003cT\u003e\u003e atLeast(int minResultsCount, [boolean cancelRemaining=true,] \n                                    CompletionStage\u003c? extends T\u003e... promises)\nstatic \u003cT\u003e Promise\u003cList\u003cT\u003e\u003e atLeast(int minResultsCount, [boolean cancelRemaining=true,] \n                                    List\u003c? extends CompletionStage\u003c? extends T\u003e\u003e promises)\n```\nGeneralization of the `any` method. Returns a promise that is completed normally when at least `minResultCount`\nof `CompletionStage`-s passed as parameters are completed normally (race is possible); if less than `minResultCount` of promises completed normally, then resulting promise is completed exceptionally.\n\n```java\nstatic \u003cT\u003e Promise\u003cList\u003cT\u003e\u003e atLeastStrict(int minResultsCount, [boolean cancelRemaining=true,] \n                                          CompletionStage\u003c? extends T\u003e... promises)\nstatic \u003cT\u003e Promise\u003cList\u003cT\u003e\u003e atLeastStrict(int minResultsCount, [boolean cancelRemaining=true,] \n                                          List\u003c? extends CompletionStage\u003c? extends T\u003e\u003e promises)\n```\nGeneralization of the `anyStrict` method. Returns a promise that is completed normally when at least `minResultCount` of `CompletionStage`-s passed as parameters are completed normally (race is possible); if any promise completed exceptionally before `minResultCount` of results are available, then resulting promise is completed exceptionally as well (unlike non-Strict variant, where exceptions are ignored if `minResultsCount` of successful results are available).\n\nAll methods above have an optional parameter `cancelRemaining` (since library's version [0.5.3](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.5.3)). When omitted, it means implicitly `cancelRemaining = true`. The `cancelRemaining` parameter defines whether or not to eagerly cancel remaining `promises` once the result of the operation is known, i.e. enough `promises` passed are settled successfully _or_ some `CompletionStage` completed exceptionally in strict version. \n\nEach operation to combine `CompletionStage`-s has overloaded versions that accept either a [List](https://docs.oracle.com/javase/8/docs/api/java/util/List.html) of `CompletionStage`-s (since version [0.5.4](https://github.com/vsilaev/tascalate-concurrent/releases/tag/0.5.4) of the library) or varagr array of `CompletionStage`-s.\n\nBesides `any`/`anyStrict` methods that return single-valued promise, all other combinator methods return a list of values per every successfully completed promise, at the same indexed position. If the promise at the given position was not settled at all, or failed (in non-strict version), then corresponding item in the result list is `null`. If necessary number or `promises` was not completed successfully, or any one completed exceptionally in strict version, then resulting `Promise` is settled with a failure of the type `MultitargetException`. Application developer may examine `MultitargetException.getExceptions()` to check what is the exact failure per concrete `CompletionStage` passed.\n\nThe `Promise` returned has the following characteristics:\n1. Cancelling resulting `Promise` will cancel all the `CompletionStage-s` passed as arguments.\n2. Default asynchronous executor of the resulting `Promise` is undefined, i.e. it could be either `ForkJoin.commonPool` or whatever `Executor` is used by any of the `CompletionStage` passed as argument. To ensure that necessary default `Executor` is used for subsequent asynchronous operations, please apply `defaultAsyncOn(myExecutor)` on the result.\n\n## 8. Polling and asynchronous retry functionality\nOnce you departure from the pure algebraic calculations to the unreliable terrain of the I/O-related functionality you have to deal with failures. Network outage, insuffcient disk space, overloaded third-party servers, exhausted database connection pools - these and many similar infrastructure failures is what application have to cope with flawlessly. And many of the aforementioned issues are temporal by the nature, so it makes sense to re-try after small delay and keep fingers crossed that this time everything will run smoothly. So this is the primary use-case for the retry functionality, or better yet -- asynchronous retry functionality, while all we want our applications be as scalable as possible.\n\nAnother related area is polling functionality - unlike infrastructure failures these are sporadic, polling is built-in in certain asynchronous protocol communications. Say, an application sends an HTTP request to generate a report and waits for the known file on FTP server. There is no \"asynchronous reply\" expected from the third-party server, and the application has to `poll` periodically till the file will be available.\n\nBoth use-case are fully supported by the Tascalate Concurrent library. The library provides an API that is both unobtrusive and rich for a wide range of tasks. The following `retry*` methods are available in the `Promises` class:\n\nProvided by utility class Promises but stands on its own\n```java\nstatic Promise\u003cVoid\u003e retry(Runnable codeBlock, Executor executor, \n                           RetryPolicy\u003c? super Void\u003e retryPolicy);\nstatic Promise\u003cVoid\u003e retry(RetryRunnable codeBlock, Executor executor, \n                           RetryPolicy\u003c? super Void\u003e retryPolicy);\n\nstatic \u003cT\u003e Promise\u003cT\u003e retry(Callable\u003cT\u003e codeBlock, Executor executor, \n                            RetryPolicy\u003c? super T\u003e retryPolicy);\nstatic \u003cT\u003e Promise\u003cT\u003e retry(RetryCallable\u003cT, T\u003e codeBlock, Executor executor, \n                            RetryPolicy\u003c? super T\u003e retryPolicy);\n    \nstatic \u003cT\u003e Promise\u003cT\u003e retryOptional(Callable\u003cOptional\u003cT\u003e\u003e codeBlock, Executor executor, \n                                    RetryPolicy\u003c? super T\u003e retryPolicy);\nstatic \u003cT\u003e Promise\u003cT\u003e retryOptional(RetryCallable\u003cOptional\u003cT\u003e, T\u003e codeBlock, Executor executor, \n                                    RetryPolicy\u003c? super T\u003e retryPolicy);\n    \nstatic \u003cT\u003e Promise\u003cT\u003e retryFuture(Callable\u003c? extends CompletionStage\u003cT\u003e\u003e invoker, \n                                  RetryPolicy\u003c? super T\u003e retryPolicy);\nstatic \u003cT\u003e Promise\u003cT\u003e retryFuture(RetryCallable\u003c? extends CompletionStage\u003cT\u003e, T\u003e invoker, \n                                  RetryPolicy\u003c? super T\u003e retryPolicy);\n```\nAll the methods from `retry` family share the same pattern. First, there is a block of code that is executed per every attempt. It could be either a full block of the asynchronous code (`retry` and `retryOptional`) or a method that returns a CompletionStage\u003cT\u003e from third-party API like Async Http library (`retryFuture`). Next, if we retry custom code block, then it's necessary to provide an `Executor` it should be run on. For `retryFuture` there is no explicit `Executor`, and it's up to the third-party library to provide scalable and robust `Executor` as a default asynchronous executor of the returned `CompletionStage`. Finally, `RetryPolicy` should be specified that provides a lot of customization options:\n1. How much attempts should be made?\n2. What is a time interval between attempts? Should it be fixed or dynamic?\n3. What is a timeout before a single attempted is considered \"hanged\"? Should it be dynamic?\n4. What exceptions are re-trieable and what are not?\n5. What result is expected to be valid? Is a `null` result valid? Is any non-`null` result valid or some returned object properties should be examined?\n    \nAll in all, `RetryPolicy` is provides an API with endless customizations per every imaginable use-case.\nBut before discussing it, it's necessary to explain a difference in each pair of methods. Why there are overloads with `Runnable` vs `RetryRunnable` and `Callable` vs `RetryCallable`? The reason is the following:\n1. Contextless retriable operations are captured as `Runnable` or `Callable` lambdas - they behaves the same for every iteration, and hence do not need a context.\n2. Methods with `RetryRunnable` and `RetryCallable` are contextual and may dynamically alter their behavior for the given iteration depending on the context passed. The `RetryContext` provides provides all necessary iteration-specific information. \n\n## 9. Partitioned processing of promises\nTBD - discuss `Promises.partitioned`\n\n## 10. Stackless sequential processing of promises\nTBD - discuss `Promises.loop(...)`\n\n## 11. Context variables \u0026 contextual Promises\n\n**WARNING** This part of API will be refactored in the upcoming release 0.9.0.\n\nAh, those dreaded `TreadLocal`-s we all hate, love to hate, but, neveretheless, use everywhere. It's quite common to store some contextual data (like authenticated user and current locale) inside `ThreadLocal` variables. Sometimes it's a custom code, sometimes the code from third-party library we can't alter. \n\nTypically, we spawn asynchronous code from some thread with well-known characteristics, like HTTP request thread. Here we can easly access contextual information from thread-local variables. However, using thread-local variables from asynchronous code block is hard while it's impossible to predict what thread from the pool will execute the code. It's necessary to capture the context of the one thread and propagate it to threads executing asynchronous code. \n\nTo solve this issue, there Tascalate Concurrent provides `ContextVar` class (since version 0.8.1), that serves as a proxy over thread-local variable for multi-threaded code. Typical usage scenario is the following:\n\n1. Define `ContextualPromiseFactory` holding `ContextVar`-s from existing thread-local variables.\n2. Capture a context of the thread that spawns asynchronous operations.\n3. Convert a `Promise` to context-aware promise.\n```java\nclass MyService {\n  // Tread-local variables; they are configured by some custom code (irrelevant for Tascalate Concurrent)\n  static final ThreadLocal\u003cPrincipal\u003e CURRENT_PRINCIPAL = new ThreadLocal\u003cPrincipal\u003e();\n  static final ThreadLocal\u003cLocale\u003e CURRENT_LOCALE = new ThreadLocal\u003cLocale\u003e();\n}\n...\n// [1] -- Define `ContextualPromiseFactory`, it's immutable, thread-safe and may be shared in any manner\nContextualPromiseFactory cpf = ContextVar.relay(MyService.CURRENT_PRINCIPAL, MyService.CURRENT_LOCALE);\n...\n// [2] -- In the invoker thread (like HTTP request thread), \n// where MyService.CURRENT_PRINCIPAL, MyService.CURRENT_LOCALE are available:\nFunction\u003cPromise\u003cString\u003e, Promise\u003cString\u003e\u003e newContextualPromise = cpf.captureContext();\n...\n// [3] -- Convert a Promise to context-aware promise with 'newContextualPromise' factory:\nPromise\u003cVoid\u003e httpRequest = \nCompletableTask.supplyAsync(() -\u003e getDownloadUrlTemplate(), myExecutor)\n               .as(newContextualPromise) // \u003c--- HERE the conversion is set \n               .thenApply(url -\u003e \n                   url + \n                   \"?user=\" + MyService.CURRENT_PRINCIPAL.getName() + \n                   \"\u0026locale=\" + MyService.CURRENT_LOCALE.toString()   \n               )\n               .thenAccept(url -\u003e {\n                 log.info(\"Get data for user \" + MyService.CURRENT_PRINCIPAL.getName());\n                 executeHttpRequest(url);\n               });\n```\nIn the example above, after the call to `Promise.as(newContextualPromise)` all of the derrived promises (i.e. code blocks in thenApply / thenAccept) may access contextual information captured in the originated thread. \n\nWorth to mention, that copying contextual variables has certain performance penalty. To stop it at the certain level, just use `Promise.raw()` to undecorate derrived promises (as with any other decorator):\n```java\nPromise\u003cVoid\u003e afterHttpRequest =\nhttpRequest.raw()\n           .thenRun(() -\u003e {\n             // MyService.CURRENT_PRINCIPAL, MyService.CURRENT_LOCALE are not available here\n           });\n```\n\n## 12. Asynchronous locks\nTBD -- `net.tascalate.concurrent.locks`\n\n## 13. Asynchronous try-with-resources\nTBD -- `Promises.tryApply` and `Promises.tryCompose`\n\n## 14. Asynchronous I/O extensions\n\n## 15. Decorators for CompletionStage / CompletableFuture / Promise\n\n## 16. Extensions to ExecutorService API\n\nIt’s not mandatory to use any specific subclasses of `Executor` with `CompletableTask` – you may use any implementation. However, someone may find beneficial to have a `Promise`-aware `ExecutorService` API. Below is a list of related classes/interfaces:\n\na. Interface `TaskExecutorService` - the specialization of [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) that uses `Promise` as a result of `submit(...)` methods.\n\nb. Class `ThreadPoolTaskExecutor` - the subclass of the standard [ThreadPoolExecutor](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html) that implements `TaskExecutorService` interface.\n\nc. Class `TaskExecutors` - a drop-in replacement for [Executors](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html) utility class that returns various useful implementations of `TaskExecutorService` instead of the standard [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html).\n\n# Acknowledgements\n\nInternal implementation details are greatly inspired [by the work](https://github.com/lukas-krecan/completion-stage) done by [Lukáš Křečan](https://github.com/lukas-krecan). The part of the polling / asynchronous retry functionality is adopted from the [async-retry](https://github.com/nurkiewicz/async-retry) library by [Tomasz Nurkiewicz](http://nurkiewicz.com/)\n\n","funding_links":[],"categories":["Uncategorized","并发编程"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvsilaev%2Ftascalate-concurrent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvsilaev%2Ftascalate-concurrent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvsilaev%2Ftascalate-concurrent/lists"}