Skip to content

feat(plugin): add user function outcome enum - #640

Open
wangyb-A wants to merge 5 commits into
mainfrom
fix/user-function-end-status-636
Open

feat(plugin): add user function outcome enum#640
wangyb-A wants to merge 5 commits into
mainfrom
fix/user-function-end-status-636

Conversation

@wangyb-A

@wangyb-A wangyb-A commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Issue Link, if available

Closes #636

Description

Replace the boolean user-function completion flag with UserFunctionOutcome, which has SUCCEEDED, FAILED, and INCOMPLETE values.

User functions now report INCOMPLETE when durable execution suspends. Normal returns report SUCCEEDED, and thrown failures report FAILED. Deprecated boolean constructor and accessor adapters preserve compatibility for existing plugin implementations.

The OTel plugins treat incomplete functions as a neutral outcome: the attempt span remains UNSET, records the INCOMPLETE attribute, and does not record the internal suspension exception. Conformance handlers and the plugin example now consume the enum directly.

Demo/Screenshots

Not applicable. This change updates the Java plugin API and lifecycle event behavior.

Checklist

  • I have filled out every section of the PR template
  • I have thoroughly tested this change

Testing

mvn clean install

Result: 1,803 tests passed with 0 failures and 0 errors. The 31 skipped tests are existing cloud-only example tests.

Unit Tests

Yes. Added converter coverage for all three outcomes and OTel tests that verify incomplete attempts remain neutral and do not record the suspension exception.

Integration Tests

Yes. Updated plugin integration tests to verify successful, failed, retried, and suspended user-function outcomes. Suspension, including a CompletionException-wrapped suspension, now asserts INCOMPLETE and exposes the unwrapped error.

Examples

Updated the existing plugin example to log outcome. No new example was needed.

@wangyb-A
wangyb-A deployed to ai-pr-review August 20, 2026 21:53 — with GitHub Actions Active
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 20, 2026 21:53 — with GitHub Actions Inactive
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 20, 2026 21:53 — with GitHub Actions Inactive
@github-actions

This comment has been minimized.

@wangyb-A
wangyb-A deployed to ai-pr-review August 20, 2026 22:11 — with GitHub Actions Active
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 20, 2026 22:11 — with GitHub Actions Inactive
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 20, 2026 22:11 — with GitHub Actions Inactive
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@wangyb-A
wangyb-A deployed to ai-pr-review August 20, 2026 22:37 — with GitHub Actions Active
@wangyb-A
wangyb-A deployed to ai-pr-review-runtime August 20, 2026 22:45 — with GitHub Actions Active
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 20, 2026 22:45 — with GitHub Actions Inactive
@github-actions

This comment has been minimized.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@wangyb-A
wangyb-A deployed to ai-pr-review August 20, 2026 23:13 — with GitHub Actions Active
@wangyb-A
wangyb-A deployed to ai-pr-review-runtime August 20, 2026 23:14 — with GitHub Actions Active
@wangyb-A
wangyb-A deployed to ai-pr-review-runtime August 20, 2026 23:14 — with GitHub Actions Active
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@wangyb-A
wangyb-A deployed to ai-pr-review August 21, 2026 18:46 — with GitHub Actions Active
@wangyb-A
wangyb-A deployed to ai-pr-review-runtime August 21, 2026 18:47 — with GitHub Actions Active
@wangyb-A
wangyb-A deployed to ai-pr-review-runtime August 21, 2026 18:47 — with GitHub Actions Active
@github-actions

Copy link
Copy Markdown

Codex AI review

One compatibility issue found. Mixed-version dynamic plugin loading is not covered by the added tests.

Reviewed commit 156059bcdf54d57b0ce5d74e88814212ba4cac91. Workflow run

@github-actions

Copy link
Copy Markdown

Claude AI review

No actionable findings. The change is correct and well-covered.

What I verified

  • Outcome classification (sdk/.../operation/BaseDurableOperation.java:359-364): unwrapCompletableFuture strips CompletionException layers, the null-cause fallback (if (error == null) error = e;) is safe, and error instanceof SuspendExecutionException correctly yields INCOMPLETE for both wrapped and direct suspensions, FAILED otherwise. The original throwable is still re-thrown via sneakyThrow(e), so retry/checkpoint/suspension propagation is unchanged — only the plugin-facing error is unwrapped.
  • Backward compatibility (UserFunctionEndInfo.java, PluginInfoConverter.java): the record's canonical constructor moved from boolean succeeded to UserFunctionOutcome outcome, but the deprecated boolean constructor and static overload preserve the old binary signatures, and the re-implemented succeeded() returns outcome == SUCCEEDED, keeping prior semantics (suspension → false). Enum vs. boolean overloads are unambiguous.
  • OTel plugins (ExecutionOtelPlugin.java, InvocationOtelPlugin.java): the switch leaves INCOMPLETE attempts UNSET and records no exception, replacing base behavior that marked suspended spans ERROR and recorded the internal SuspendExecutionException. Matches the README table and new tests.
  • Call-site migration: all info.succeeded() consumers (conformance plugins, example, integration/unit tests) were migrated; no un-migrated callers remain, and the deprecated accessor exists only for external compatibility.

Residual test risk
The unwrapCompletableFuture call applies to every failure, not just suspensions, so a genuine (non-suspension) error wrapped in CompletionException now reports its unwrapped cause to plugins/OTel instead of the wrapper. This is a reasonable improvement, but it is a behavior change beyond the suspension fix described in the PR and is exercised only for the suspension case (plugin_userFunctionEnd_unwrapsCompletionExceptionForSuspension); there is no test asserting a wrapped genuine FAILED error surfaces its unwrapped cause. Consider adding one to lock in the intended behavior.

Reviewed commit 156059bcdf54d57b0ce5d74e88814212ba4cac91. Workflow run

@wangyb-A
wangyb-A marked this pull request as ready for review August 21, 2026 20:20
@wangyb-A
wangyb-A requested a review from a team August 21, 2026 20:20
@wangyb-A
wangyb-A requested a deployment to ai-pr-review-runtime August 21, 2026 20:20 — with GitHub Actions In progress
@wangyb-A
wangyb-A deployed to ai-pr-review-runtime August 21, 2026 20:20 — with GitHub Actions Active
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

Successfully merging this pull request may close these issues.

[Feature]: Add a enum type for user function end

1 participant