From 2a41ed0b5dccbd841b7ff6a64a0ce76893bdf526 Mon Sep 17 00:00:00 2001 From: Junchuan Wang Date: Tue, 16 Feb 2021 10:41:46 -0800 Subject: [PATCH 1/5] Add transformWith to Task API which performs transformation with a task --- .../main/java/com/linkedin/parseq/Task.java | 99 +++++++++++++++++++ .../java/com/linkedin/parseq/TaskType.java | 2 + .../com/linkedin/parseq/AbstractTaskTest.java | 56 +++++++++++ 3 files changed, 157 insertions(+) diff --git a/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java b/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java index 7e275703..400e50b8 100644 --- a/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java +++ b/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java @@ -550,6 +550,45 @@ default Task andThen(final Consumer1 consumer) { return andThen("andThen: " + _taskDescriptor.getDescription(consumer.getClass().getName()), consumer); } + /** + * Create a new task which applies a function to the result of "calling task". The function will have to return another task. + * If {@param triggerReturnTask} is enabled, the task returned by the function will be run as part of the plan as well. + * If {@param triggerReturnTask} is not enabled, the result of the new task will be that function output, similar to {@link #flatMap(Function1)} + * + * @param desc description to the returned task + * @param func the function that takes the result of calling task as a parameter and returns another task + * @param triggerReturnTask whether want to execute the task returned by the function + * @return a new task + */ + default Task andThen(final String desc, final Function1> func, boolean triggerReturnTask) { + if (!triggerReturnTask) { + return flatMap(func); + } + ArgumentUtil.requireNotNull(func, "func"); + final Task that = this; + return async("andThenRun", context -> { + SettablePromise promise = Promises.settable(); + Task asyncWrapperTask = async("", ctx-> { + SettablePromise asyncWrapperTaskPromise = Promises.settable(); + Task taskToRun = null; + if (!that.isFailed()) { + taskToRun = func.apply(that.get()); + if (taskToRun == null) { + throw new RuntimeException(desc + " returned null"); + } else { + ctx.run(taskToRun); + } + } + Promises.propagateResult(taskToRun, asyncWrapperTaskPromise); + return asyncWrapperTaskPromise; + }); + context.after(that).run(asyncWrapperTask); + context.run(that); + Promises.propagateResult(asyncWrapperTask, promise); + return promise; + }); + } + /** * Creates a new task which runs given task after * completion of this task and completes with a result of @@ -845,6 +884,66 @@ default Task transform(final Function1, Try> func) { return transform("transform: " + _taskDescriptor.getDescription(func.getClass().getName()), func); } + /** + * Create a new task that will transform the result of this task. + * Returned task will complete with value calculated by a task returned by the function. + * + * This is similar to {@link #transform(String, Function1)} except the transformation is done by executing the task returned + * by the function. + * + * @param desc description + * @param func function to be applied to the result of this task which returns new task + * to be executed + * @param value type of the returned task returned by function func< + * @return a new task which will apply given function on result of either successful and failed completion of this task + * to get instance of a task which will be executed next + */ + default Task transformWith(final String desc, final Function1, Task> func) { + ArgumentUtil.requireNotNull(func, "function"); + final Task that = this; + Task transformWithTask = async(desc, context -> { + final SettablePromise result = Promises.settable(); + final Task transform = async("transform", ctx -> { + final SettablePromise transformResult = Promises.settable(); + if (that.isFailed() && (Exceptions.isCancellation(that.getError()))) { //not treating cancellations as errors + transformResult.fail(that.getError()); + } + else { + final Try tryT = Promises.toTry(that); + try { + Task r = func.apply(tryT); + if (r == null) { + throw new RuntimeException(desc + " returned null"); + } + Promises.propagateResult(r, transformResult); + ctx.run(r); + } catch (Throwable t) { + transformResult.fail(t); + } + } + return transformResult; + }); + transform.getShallowTraceBuilder().setSystemHidden(true); + transform.getShallowTraceBuilder().setTaskType(TaskType.TRANSFORM.getName()); + Promises.propagateResult(transform, result); + context.after(that).run(transform); + context.run(that); + return result; + }); + transformWithTask.getShallowTraceBuilder().setTaskType(TaskType.WITH_TRANSFORM.getName()); + return transformWithTask; + + } + + /** + * Equivalent to {@code transformWith("transformWith", func)}. + * @see #transformWith(String, Function1) + */ + default Task transformWith(final Function1, Task> func) { + return transformWith("transform: " + _taskDescriptor.getDescription(func.getClass().getName()), func); + } + + /** * Creates a new task that will handle failure of this task. * Early completion due to cancellation is not considered to be a failure so it will not be recovered. diff --git a/subprojects/parseq/src/main/java/com/linkedin/parseq/TaskType.java b/subprojects/parseq/src/main/java/com/linkedin/parseq/TaskType.java index 4e385e9a..d8b63ac4 100644 --- a/subprojects/parseq/src/main/java/com/linkedin/parseq/TaskType.java +++ b/subprojects/parseq/src/main/java/com/linkedin/parseq/TaskType.java @@ -16,6 +16,8 @@ public enum TaskType { WITH_TIMEOUT ("withTimeout"), RECOVER ("recover"), WITH_RECOVER ("withRecover"), + TRANSFORM ("transform"), + WITH_TRANSFORM ("withTransform"), WITH_DELAY ("withDelay"); private final String _name; diff --git a/subprojects/parseq/src/test/java/com/linkedin/parseq/AbstractTaskTest.java b/subprojects/parseq/src/test/java/com/linkedin/parseq/AbstractTaskTest.java index dedfe288..afaafa19 100644 --- a/subprojects/parseq/src/test/java/com/linkedin/parseq/AbstractTaskTest.java +++ b/subprojects/parseq/src/test/java/com/linkedin/parseq/AbstractTaskTest.java @@ -439,6 +439,62 @@ public void testTransformFailureToFailure() { assertSame(transformed.getError(), failureReason); } + @Test + public void testTransformWith_SuccessToFailure() { + String msg = "transform failed"; + Task success = getSuccessTask(); + Task transformed = success.transformWith(tryT -> + Task.callable(() -> {throw new RuntimeException(msg);})); + try { + runAndWait("AbstractTaskTest.testTransformWith_SuccessToFailure", transformed); + } catch (Exception ex) { + assertEquals(ex.getCause().getMessage(), msg); + } + } + + @Test + public void testTransformWith_SuccessToSuccess() { + Task success = getSuccessTask(); + Task transformed = success.transformWith(tryT -> + Task.callable(() -> tryT.get().length())); + runAndWait("AbstractTaskTest.testTransformWith_SuccessToSuccess", transformed); + assertEquals(transformed.get().intValue(), success.get().length()); + } + + @Test + public void testTransformWith_FailureToSuccess() { + int returnValue = 100; + Task failed = getFailureTask(); + Task transformed = failed.transformWith(tryT -> + Task.callable(() -> returnValue)); + runAndWait("AbstractTaskTest.testTransformWith_FailureToSuccess", transformed); + } + + @Test + public void testTransformWith_FailureToFailure() { + String msg = "transform failed"; + Task failed = getFailureTask(); + Task transformed = failed.transformWith(tryT -> + Task.callable(() -> {throw new RuntimeException(msg);})); + try { + runAndWait("AbstractTaskTest.testTransformWith_FailureToFailure", transformed); + } catch (Exception ex) { + assertEquals(ex.getCause().getMessage(), msg); + } + } + + @Test + public void testTransformWith_Cancelled() { + Task cancelled = getCancelledTask().recoverWith(e -> Task.callable("recover success", () -> "recovered")); + try { + runAndWait("AbstractTaskTest.testTransformWith_Cancelled", cancelled); + fail("should have failed"); + } catch (Exception ex) { + assertTrue(cancelled.isFailed()); + assertTrue(Exceptions.isCancellation(cancelled.getError())); + } + } + @Test public void testFlatten() { Task> nested = Task.callable(() -> getSuccessTask()); From 3e6ffae8eeb5434de38393b244c741eb127917f3 Mon Sep 17 00:00:00 2001 From: Junchuan Wang Date: Tue, 16 Feb 2021 10:49:07 -0800 Subject: [PATCH 2/5] add changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfc553e8..6de7e0f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ +v5.1.2 +------ + v5.1.1 ------ +* Add "transformWith" to Task API which performs transformation by executing a task v5.1.0 ------ From bf6dde10c5195201349eec2e2f4abb7e8358a858 Mon Sep 17 00:00:00 2001 From: Junchuan Wang Date: Tue, 16 Feb 2021 10:50:01 -0800 Subject: [PATCH 3/5] delete unrelated change --- .../main/java/com/linkedin/parseq/Task.java | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java b/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java index 400e50b8..a36dc5d6 100644 --- a/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java +++ b/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java @@ -550,45 +550,6 @@ default Task andThen(final Consumer1 consumer) { return andThen("andThen: " + _taskDescriptor.getDescription(consumer.getClass().getName()), consumer); } - /** - * Create a new task which applies a function to the result of "calling task". The function will have to return another task. - * If {@param triggerReturnTask} is enabled, the task returned by the function will be run as part of the plan as well. - * If {@param triggerReturnTask} is not enabled, the result of the new task will be that function output, similar to {@link #flatMap(Function1)} - * - * @param desc description to the returned task - * @param func the function that takes the result of calling task as a parameter and returns another task - * @param triggerReturnTask whether want to execute the task returned by the function - * @return a new task - */ - default Task andThen(final String desc, final Function1> func, boolean triggerReturnTask) { - if (!triggerReturnTask) { - return flatMap(func); - } - ArgumentUtil.requireNotNull(func, "func"); - final Task that = this; - return async("andThenRun", context -> { - SettablePromise promise = Promises.settable(); - Task asyncWrapperTask = async("", ctx-> { - SettablePromise asyncWrapperTaskPromise = Promises.settable(); - Task taskToRun = null; - if (!that.isFailed()) { - taskToRun = func.apply(that.get()); - if (taskToRun == null) { - throw new RuntimeException(desc + " returned null"); - } else { - ctx.run(taskToRun); - } - } - Promises.propagateResult(taskToRun, asyncWrapperTaskPromise); - return asyncWrapperTaskPromise; - }); - context.after(that).run(asyncWrapperTask); - context.run(that); - Promises.propagateResult(asyncWrapperTask, promise); - return promise; - }); - } - /** * Creates a new task which runs given task after * completion of this task and completes with a result of From 487e1f5ef4805afff6e846a4e9fe581588af702b Mon Sep 17 00:00:00 2001 From: Junchuan Wang Date: Tue, 16 Feb 2021 11:52:45 -0800 Subject: [PATCH 4/5] address comments --- gradle.properties | 2 +- .../src/main/java/com/linkedin/parseq/Task.java | 15 +++++++++++++++ .../parseq/doc-files/transformWith-1.png | Bin 0 -> 26766 bytes 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 subprojects/parseq/src/main/java/com/linkedin/parseq/doc-files/transformWith-1.png diff --git a/gradle.properties b/gradle.properties index 132e0243..86e1e8e3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version=5.1.0 +version=5.1.1 group=com.linkedin.parseq org.gradle.parallel=true diff --git a/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java b/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java index a36dc5d6..fb24d8d6 100644 --- a/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java +++ b/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java @@ -852,6 +852,21 @@ default Task transform(final Function1, Try> func) { * This is similar to {@link #transform(String, Function1)} except the transformation is done by executing the task returned * by the function. * + *
+   * boolean writeToDB(String content) {...}
+   *
+   * Task{@code } pictureBase64= ...
+   *
+   * // this task will complete with either complete successfully
+   * // with uploadResult either true or false, or fail with  MyLibException
+   * Task{@code } uploadResult = pictureBase64.transformWith("transformUsingATask", t {@code ->} {
+   *   if (!t.isFailed()) {
+   *     return Task.blocking(() -> writeToDB(t.get()), executor));
+   *   }
+   *   return Task.failure(new MyLibException(t.getError());
+   * });
+   * 
+   *
    * @param desc description
    * @param func function to be applied to the result of this task which returns new task
    *    to be executed
diff --git a/subprojects/parseq/src/main/java/com/linkedin/parseq/doc-files/transformWith-1.png b/subprojects/parseq/src/main/java/com/linkedin/parseq/doc-files/transformWith-1.png
new file mode 100644
index 0000000000000000000000000000000000000000..bc51bd78847fa2db519ace5d37fe7b21b963c43d
GIT binary patch
literal 26766
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�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 x+yXAr*>rcX{ij^`x^x=%U(@2hl}=v~dKNsm Date: Tue, 16 Feb 2021 23:10:52 -0800 Subject: [PATCH 5/5] address comments --- .../parseq/src/main/java/com/linkedin/parseq/Task.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java b/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java index fb24d8d6..fcd8b186 100644 --- a/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java +++ b/subprojects/parseq/src/main/java/com/linkedin/parseq/Task.java @@ -858,7 +858,7 @@ default Task transform(final Function1, Try> func) { * Task{@code } pictureBase64= ... * * // this task will complete with either complete successfully - * // with uploadResult either true or false, or fail with MyLibException + * // with uploadResult being true or false, or fail with MyLibException * Task{@code } uploadResult = pictureBase64.transformWith("transformUsingATask", t {@code ->} { * if (!t.isFailed()) { * return Task.blocking(() -> writeToDB(t.get()), executor)); @@ -881,7 +881,8 @@ default Task transformWith(final String desc, final Function1, Tas final SettablePromise result = Promises.settable(); final Task transform = async("transform", ctx -> { final SettablePromise transformResult = Promises.settable(); - if (that.isFailed() && (Exceptions.isCancellation(that.getError()))) { //not treating cancellations as errors + if (that.isFailed() && (Exceptions.isCancellation(that.getError()))) { + //cancellations will not be propagated as other errors to the function to get the task to execute. transformResult.fail(that.getError()); } else {