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

[improve][misc] Return failed future in async method instead of throw exception directly #20521

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Shawyeok
Copy link
Contributor

@Shawyeok Shawyeok commented Jun 7, 2023

Motivation

Throws an exception from a async method generally a bad practice, for example in ProducerBuilderImpl#createAsync, checkArgument may throws a runtime exception directly:

public CompletableFuture<Producer<T>> createAsync() {
// config validation
checkArgument(!(conf.isBatchingEnabled() && conf.isChunkingEnabled()),
"Batching and chunking of messages can't be enabled together");

If user call it in a async context, it may cause some unexpected behavior, here is a case:

CompletableFuture<xxx> future = new CompletableFuture<>();
xxx.whenComplete((v, ex) -> {
    xxx.createAsync().whenComplete((v, ex) -> {
        if (ex != null) {
            future.completeExceptionally(ex);
        } else {
            future.complete(v);
        }
    });
})

If createAsync() throws an exception from inside, the future will never get completed. This kind of problem is very hard to troubleshooting cause it could haven’t any log.

So I wrote a PMD rule to examine the entire Pulsar codebase (current master branch), aiming to identify similar kinds of problems. Here it is:

//MethodDeclaration[matches(@Name, "Async$")]
  [.//PrimaryPrefix/Name[matches(@Image, "(requireNonNull|checkNotNull|checkState|checkArgument)$")]]

Note: this rule may not be able to scan all similar code issues.

Modifications

Return a failed future instead of throw exception directly, for the given case above, it's will be change to:

public CompletableFuture<Producer<T>> createAsync() {
    // config validation
    if (conf.isBatchingEnabled() && conf.isChunkingEnabled()) {
        return FutureUtil.failedFuture(
                new IllegalArgumentException("Batching and chunking of messages can't be enabled together"));
    }

Verifying this change

  • Make sure that the change passes the CI checks.

Does this pull request potentially affect one of the following parts:

If the box was checked, please highlight the changes

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

Documentation

  • doc
  • doc-required
  • doc-not-needed
  • doc-complete

Matching PR in forked repository

PR in forked repository: Shawyeok#9

@github-actions github-actions bot added the doc-not-needed Your PR changes do not impact docs label Jun 7, 2023
@lhotari
Copy link
Member

lhotari commented Jun 7, 2023

Thanks for the contribution.

This is a breaking change in the API since exceptions could also be considered as part of the API although they aren't explicitly stated in the Java interface files. We use the PIP process to track changes to public APIs in Pulsar.

The other benefit of a PIP is that there will be broader awareness of the change in our approach to handle method parameter validation in asynchronous methods. The PIP process will help ensure better consistently in the project in the future.

@Shawyeok please start a new PIP for this change.

Copy link
Member

@lhotari lhotari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking the changes since I think that we need a PIP for public API changes. I provided the rational in my previous comment.

@github-actions
Copy link

github-actions bot commented Jul 8, 2023

The pr had no activity for 30 days, mark with Stale label.

@github-actions github-actions bot added the Stale label Jul 8, 2023
@Technoboy- Technoboy- added this to the 3.2.0 milestone Jul 31, 2023
@Technoboy- Technoboy- modified the milestones: 3.2.0, 3.3.0 Dec 22, 2023
@coderzc coderzc modified the milestones: 3.3.0, 3.4.0 May 8, 2024
@lhotari lhotari modified the milestones: 4.0.0, 4.1.0 Oct 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc-not-needed Your PR changes do not impact docs Stale
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants