Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 03:36

    jhalterman on gh-pages

    Add Trino and Tibco (compare)

  • 03:33

    jhalterman on gh-pages

    Add Trino (compare)

  • Jan 15 22:25
    Fadelis commented #221
  • Jan 15 22:23
    Fadelis commented #221
  • Oct 30 2020 21:04
    chadselph commented #159
  • Oct 29 2020 07:36
    chadselph commented #159
  • Oct 26 2020 12:44
    marcphilipp opened #266
  • Oct 03 2020 13:21
    Tembrel commented #252
  • Oct 03 2020 03:36
    Tembrel commented #252
  • Oct 02 2020 18:27
    robertvazan commented #252
  • Oct 02 2020 17:49
    hkupty commented #252
  • Oct 02 2020 17:25
    Tembrel commented #252
  • Oct 02 2020 09:14
    hkupty commented #252
  • Oct 02 2020 07:43
    whiskeysierra commented #252
  • Oct 02 2020 07:39
    hkupty commented #252
  • Oct 02 2020 07:15
    whiskeysierra commented #252
  • Oct 01 2020 22:02
    hkupty commented #252
  • Oct 01 2020 17:22

    jhalterman on master

    Upgrade to netty-all 4.1.51.Fin… (compare)

  • Oct 01 2020 17:22
    jhalterman closed #259
  • Sep 28 2020 12:14
    odidev commented #259
Willi Schönborn
@whiskeysierra
So in case you have at least one retry (caused by at least one exception) you want to have both the error and response variable bet set and inspect both to create your result?
thierryb180381
@thierryb180381

Hello,

For example, it makes a first call :

  • if it succeeds, it's ok. I will use the response to build my final response
  • if it fails (because of any exception), then catch Exception, because I don't want a big stack trace, and retries according to maxTries.
    At the end, if it's always failed, be able to retrieve the last exception error in variable error, and use it to build my final response that will contain that error message.

I hope, it's more clear.

Thank you.

Jonathan Halterman
@jhalterman
@thierryb180381 If you want to catch an exception and replace it with something else, or suppress it, you can use a fallback outside of your retry policy. This is not much different than using a catch block, but something like:
Fallback<String> fallback = Fallback.of(e -> {
  // Build and return an error string when the execution fails
  return buildResponse(e.getLastFailure().toString());
});

Failsafe.with(fallback, retryPolicy).get(() -> myService.call(request));
thierryb180381
@thierryb180381
Hello @jhalterman , thank you for your answer, it works perfectly :).
Jonathan Halterman
@jhalterman

Time based circuit breakers have been merged to master and are set to be released. If you want to have a look and request any changes before the release, now is the time :)

The commit is: jhalterman/failsafe@c4ce4a0
The commit for the website docs is: jhalterman/failsafe@fc53532

Jonathan Halterman
@jhalterman
Failsafe 2.4.0 was released, which includes time based circuit breakers: https://jodah.net/failsafe/circuit-breaker/#configuration
Clifton T. Mtengezo
@tikomtengezo_twitter

I have a situation:

  1. When I send an http request e.g. makePayment, I can get
    a. Success e,g, http status 200
    b. Failure e.g. http status other than 200
    c. Exception e.g. Connect Timeout, GateWay Timeout

  2. When I get a success or a filure, I will work with it and return to the client

  3. When I get an exception, mainly Gateway Timeout exception, I do NOT want to return it. I do NOT want to repeat the original request (makePayment), I want to send a completely new request e.g. confirmPayment to a different end point.

  4. So the result of the makePayment request can either be response obtained after first attempt if it was successful or response obtained from repeatedly (3 times) sending confirmPayment request.

How can I achieve this with Failsafe?
My apologies I am new to Failsafe. If this question was already asked, direct me to the answer.

Thank you in advance.

Jon Harkness
@ness2u
I found a bug in some library, that happens to use Failsafe for retries. I'm trying to update that library, by continuing to use Failsafe for retries, but making it proper non-blocking/async...
The only formal sample I see is https://jodah.net/failsafe/async-api/ but it isn't complete... is there a better sample, including the policy, to handle proper async retries?
Jonathan Halterman
@jhalterman

@ness2u That example is lacking a better explanation, but basically since we're async, you need to manually indicate when you want to schedule a retry via one of the retry methods. You an also, optionally, attempt to complete the execution (and the associated future) via the complete methods. The retry methods that take arguments will do both - attempt to complete the execution, else retry. https://jodah.net/failsafe/javadoc/net/jodah/failsafe/AsyncExecution

Most of the complete/retry methods return boolean, which indicates whether the execution could be completed or whether a retry was successfully scheduled, both of which are based on the RetryPolicy.

5 replies
Jonathan Halterman
@jhalterman

@tikomtengezo_twitter The most common way to change a request for a retry is something like this:

    RetryPolicy<HttpResponse> retryPolicy = new RetryPolicy<HttpResponse>().withMaxAttempts(4).handle(GatewayTimeoutException.class);
    Failsafe.with(retryPolicy).get(ctx -> {
      if (ctx.isFirstAttempt())
        makePayment();
      else
        confirmPayment();
    });

This might not be perfect if GatewayTimeoutException only occurs when calling makePayment and the failure is something else when calling confirmPayment, but you could probably tweak the RetryPolicy to deal with this.

Another option is to use two Failsafe calls, the first one with a Fallback which makes the second request using retries. Ex:

    Fallback<HttpResponse> fallback = Fallback.of(e -> {
      RetryPolicy<HttpResponse> retryPolicy = new RetryPolicy<HttpResponse>().withMaxAttempts(3);
      Failsafe.with(retryPolicy).get(() -> confirmPayment);
    }).handle(GatewayTimeoutException.class);
    Failsafe.with(fallback).get(() -> makePayment());
madamanv
@madamanv
Hi, i want to use failsafe with retry policy to trigger async calls, one thing that bothers me to use this library is, i don't see any documentation on how to keep async threads under control, this is to keep failsafe not to use all available threads for async calls. can you please tell if there is a way i can restrict number of async threads i can span
Jonathan Halterman
@jhalterman
@madamanv If you provide your own ScheduledExecutorService or thread pool (.with(threadPool)), you can control how many threads are available to that pool. If you don't provide this, then Failsafe uses the JDK's common pool which is sized based on the number of cores supported by the machine (# of CPUs minus 1).
Rajesh Raman
@amogh_prahar_twitter
Hello - I'm trying to use failsafe in an async style for my project but am hitting a conceptual problem. I'd like to issue an async HttpRequest.
Failsafe
  .with(policy)
  .getAsyncExecution(
     execution -> {
       logger.debug("executing request {}", request);
       httpClient.execute(request, new FutureCallback<HttpResponse>() {
         @Override
         public void completed(HttpResponse response) {
           execution.complete(response);
         }
         @Override
         public void failed(Exception e) {
           logger.error("exception executing request (attempt {}) {}", execution.getAttemptCount(), request, e);
           execution.retryOn(e);
         }
         @Override
         public void cancelled() {
           execution.complete();
         }
       });
       // XXX: What does failsafe expect to have returned here??
     }
   );
Jonathan Halterman
@jhalterman
@madamanv Failsafe expects a ScheduledFuture to be returned (which is what ScheduledExecutorService normally returns). There's a DefaultScheduledFuture class you can use for convenience. Admittedly, this is something that needs a bit of improvement as I'm not sure returning anything should be necessary.
Rajesh Raman
@amogh_prahar_twitter
Hello - it seems like AsyncExecution.complete returns true if (a) the request was successfully executed, or (b) if we ran out of retries. Is there some way differentiate between the two situations, short of looking at the policy and comparing to the attempt count (which is a bit ugly in my opinion)?
Jonathan Halterman
@jhalterman
@amogh_prahar_twitter .complete does not evaluate whether more retries are possible, only if the result is a success or not. Retries are evaluated when you call one of the retry methods.
If you have any suggestions for how the AsyncExecution APIs might be improved to work more clearly, I'd love to hear. Feel free to file an issue if you do.
Rajesh Raman
@amogh_prahar_twitter
@jhalterman - if .complete returns if the result is a success I think there might be a bug. Consider this example:
    public void testRetry() throws ExecutionException, InterruptedException {
        RetryPolicy<Integer> policy = new RetryPolicy<Integer>().withMaxRetries(5).handleResultIf(i -> i < 10);
        AtomicInteger number = new AtomicInteger();
        Failsafe.with(policy).with(executorService).getAsyncExecution(execution -> {
                    CompletableFuture.completedFuture(number.getAndIncrement()).handle((response, error) -> {
                        if (execution.complete(response)) {
                            System.out.println("success; got " + response);
                        } else if (execution.retry()) {
                            System.out.println("retrying; got " + response);
                        } else {
                            System.out.println("out of retries; last got " + response);
                        }
                        return response;
                    });
                    return null;
                }
        ).get();
    }
The intention is that values less than 10 need a retry but in this case I have only 5 retries.
The output I get is
retrying; got 0
retrying; got 1
retrying; got 2
retrying; got 3
retrying; got 4
success; got 5
Jonathan Halterman
@jhalterman
withMaxRetries(5) would do that wouldn't it?
Rajesh Raman
@amogh_prahar_twitter
shouldn't .complete return false in that case?
Jonathan Halterman
@jhalterman
yea i think it should, since the handleResultIf condition is not satisfied
i agree this looks like a bug
do you mind filing an issue for this?
Rajesh Raman
@amogh_prahar_twitter
Sure will do - thanks for the prompt replies.
Jonathan Halterman
@jhalterman
@amogh_prahar_twitter Arg, sorry, I was wrong. The complete result is meant to indicate just that execution is complete, in this case because retries are exhausted. It doesn't necessarily indicate success or failure.
Rajesh Raman
@amogh_prahar_twitter
Ah ok. That brings back my question: how to differentiate between the two situations?
Jonathan Halterman
@jhalterman

From inside your AsyncSupplier impl I don't think there is a good way currently to learn if the execution was successful, only if it was complete. The way the API was designed, the AsyncSupplier was meant to just perform some task. Inspecting whether the result of the task is successful or not can be done externally, via a listener or by checking the Future's result.

https://jodah.net/failsafe/event-listeners/

Do you have a use case for wanting to know if the execution was successful from inside the AsyncSupplier?
Rajesh Raman
@amogh_prahar_twitter
I would like to return a different result from the supplier, and count success/failures/retries/etc. in a localized manner. I also think it would generally be convenient to have a .completedSuccessfully method since the AsyncExecution actually has this information already.
Rajesh Raman
@amogh_prahar_twitter
But it looks like the event listeners will work well enough. Thanks!
Jonathan Halterman
@jhalterman
:thumbsup:
Manish Jain
@sahihaimanish_twitter

Hi, I was testing this library through a JUnit test case where there were two tasks in CompletableFuture.runAsync() and both fail after 2 retries with Failsafe. I noticed that when the task starts it uses two workers 'ForkJoinPool.commonPool-worker-1' and 'ForkJoinPool.commonPool-worker-2' (since we are using the default ThreadPool) but when the retries happen, it is only carried out by one of the workers. Any idea why this is happening? Is it even async if only one worker is switching and doing tasks?

I tried with 4 tasks too, same issue.

Jonathan Halterman
@jhalterman
@sahihaimanish_twitter Failsafe will only perform one retry at a time for some execution. I'm not sure exactly how the two tasks you mention relate to failsafe. Can you post a bit of example code?
Manish Jain
@sahihaimanish_twitter
@jhalterman Here, eventObject consists of multiple items.
List<CompletableFuture<Void>> completableFutures = eventObject.batch.stream().map(metric -> {
                    return (CompletableFuture<Void>) Failsafe.with(retryPolicy).runAsync(() -> {
                        String metricString = metric.getMetric();
                        try {
                            sendDataToMetricStore();
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    });
            }).collect(Collectors.toList());
Manish Jain
@sahihaimanish_twitter
I get that failsafe is applied per item in this case but why it is picking the same worker thread?
Like, runAsync() will pick worker-1, worker-2, and worker-3 (say, for 3 tasks) but Failsafe retry will always pick worker-2 for all its retries. Doesn't that make the retry slower in this case?
Nguyen Anh Tuan
@tuannguyen7
Hi, do I need to create a new RetryPolicy every time or I can create only one instance and safely use it.
Jonathan Halterman
@jhalterman
@tuannguyen7 yep, you can reuse policies and it's ideal to do so. BUT, worth noting that RetryPolicy is not threadsafe. So you wouldn't want to modify it from different threads.
Nguyen Anh Tuan
@tuannguyen7
Thank you @jhalterman
Nguyen Anh Tuan
@tuannguyen7
There is any clever way to throw a checked exception if max retries exceeded. I know that Fallback can be used but I want to declare the exception in method signature. My code looks like this but seems like it's a bit ugly.
public Product getProduct(int id) throw ClientException {
    try {
      return Failsafe.with(retryPolicy).get(() -> tryGettingProduct(id));
   } catch (FailsafeException e) {
      if (e.getCause() instanceof ClientException)
        throw (ClientException)e.getCause();
      throw e;
   }
}

private Product tryGettingProduct(int id) throw ClientException {
     // code ...
}
Sarah
@BaiyuY

Hi all, I was using an old version of failsafe(1.0.0), configured a circuitbreaker with no delay. the code inside the circuit breaker hasn't been enable to execute, so it basically looks like

failsafe.run(() -> {
  if (!Strings.isNullOrEmpty("someString")) {
      //do nothing
  }
}
CircuitBreaker circuitBreaker = new CircuitBreaker()
                .failOn(TimeoutException.class)
                .withFailureThreshold(Integer.parseInt(1), Integer.parseInt(10))
                .withSuccessThreshold(Integer.parseInt(5))
                .withTimeout(Integer.parseInt(10), TimeUnit.MILLISECONDS);

        circuitBreaker.onOpen(() -> System.out.println("Circuit Breaker opened"));
        circuitBreaker.onHalfOpen(() -> System.out.println("Circuit Breaker half-opened"));
        circuitBreaker.onClose(() -> System.out.println("Circuit Breaker closed"));

I configured the circuitbreaker with 10ms timeout. which a simple strings null check shouldn't take that long. But I am see the log of constant rotation of "Circuit Breaker open" then half open, then closed, and Repeat.

This is in a multi-threading env, I am wondering if anyone can explain this behaviour? Thanks!

And I am curious with 2.40, is the counting of failure thread-safe? (not plan to modify the circuit breaker policy inside different threads)
Sarah
@BaiyuY
@jhalterman much appreciated if you could help :)
swordsp
@swordsp
Hi everyone, I have a question about the FailsafeExecutor. From its comment it looks like the command wrapped by the executor would be executed in an extra background thread, either from commonPool or a given ExecutorService. Is it possible that we still execute it in current thread to reduce the overhead?
Joy Hou
@strawbee
Hi all. Is there a way to test the circuit breaker in "shadow mode" (just emit metrics that the circuit breaker is open, but not actually prevent calls to the dependency) so that I can test the thresholds configuration for a while, without actually affecting my service?
Jonathan Halterman
@jhalterman
@swordsp Executions are sync (in the current thread) or async (on the common pool or some other pool you configure), depending on which terminal method you use. Ex: get vs getAsync. So for synchronous, just use the run or get methods.
Jonathan Halterman
@jhalterman

@strawbee Nothing like that exists atm. You could pretty easily override CircuitBreaker and CircuitBreakerExecutor with your own impls to accomplish this though. First, extend CircuitBreakerExecutor and return null during preExecute:

https://github.com/jhalterman/failsafe/blob/master/src/main/java/net/jodah/failsafe/CircuitBreakerExecutor.java#L34

Then extend CircuitBreaker to return your customer CircuitBreakerExecutor:

https://github.com/jhalterman/failsafe/blob/master/src/main/java/net/jodah/failsafe/CircuitBreaker.java#L666

3 replies
Joy Hou
@strawbee
Hi @jhalterman, I had another question if you could help :) What order should the policies be composed in if I want to specify a slow call timeout that counts as a failure in my circuit breaker, but I also want it to retry with the same timeout? If I do:
Failsafe.with(fallback, retryPolicy, circuit breaker, timeout) like in the docs, will the retry timeout as well before it returns the fallback? Thanks a ton.
9 replies
Jon Bates
@spadger
This message was deleted