Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed promise before calling allOf is not failing the wrapped promise. #2046

Open
awx-michael-wang opened this issue Apr 29, 2024 · 3 comments

Comments

@awx-michael-wang
Copy link

awx-michael-wang commented Apr 29, 2024

Expected Behavior

Promise.allOf(promises) should fail as long as one of the promises fails, no matter it is already failed before calling the allOf or after.

Actual Behavior

If one Promise in promises is already failed before calling allOf, the failure is ignored.

How to reproduce

A workflow like following will ended successfully.

        val promise1 = Async.procedure { throw RuntimeException() }
        val promise2 = Async.procedure {
            // do something else
        }
        someActivity.doSomething()

        Promise.allOf(promise1, promise2).get()

Analysis

AllOfPromise#addPromise only handles the promise that is not completed.

Specifications

  • Version: 1.20.0
@Quinn-With-Two-Ns
Copy link
Contributor

Yes this is a bug, looks like we ignore the promise if it has completed regardless of how it completed

We should check if it has completed exceptionally or not.

Fixing this though could break backwards compatibility since this could effect workflow code. Any fix will need to make sure to preserve history compatibility with workflows that have this scenario.

@Quinn-With-Two-Ns
Copy link
Contributor

In the mean time the easiest way to workaround this bug I think is to implement a wrapper around promiseAllOf to check if any promise passed in failed

static Promise<Void> allOf(Promise<?>... promises) {
  for (Promise<?> p : promises) {
      if (p.isCompleted() && p.getFailure() != null) {
        return Workflow.newFailedPromise(p.getFailure());
      }
    }
    return WorkflowInternal.promiseAllOf(promises);
  }
}

@awx-michael-wang
Copy link
Author

awx-michael-wang commented May 6, 2024

Thank you. I did implement a similar wrapper:

fun <T> List<Promise<T>>.safeAllOf(): Promise<Void> {
    val existFailure = this.filter { it.isCompleted }
        .firstNotNullOfOrNull { it.failure }

    return if (existFailure != null) {
        Workflow.newFailedPromise(existFailure)
    } else {
        Promise.allOf(this)
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants