Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Finagle Retry Behavior
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  7 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Walter Blaurock  
View profile  
 More options Jul 27 2012, 2:19 pm
From: Walter Blaurock <wal...@thenextbigsound.com>
Date: Fri, 27 Jul 2012 11:19:31 -0700 (PDT)
Local: Fri, Jul 27 2012 2:19 pm
Subject: Finagle Retry Behavior

Hello,

I have been using Finagle (with Java) for a few weeks, and have had a lot
of success with it. However, I'm having trouble wrapping my head around the
failover/retry behavior in my clients. It is my understanding that, by
default, Finagle will only retry a client request if nothing has been
written out on the wire to avoid issues with non-idempotent methods. I
certainly agree with this default behavior, but I'm looking for a way to
modify it (to retry all failures, for example). I was hoping that either
retryPolicy or retryFilter would help me out, but the first appears to deal
with backing off of subsequent retries, and I'm unable to find
documentation/samples for the second.

What is wish to accomplish is:

   1. start server / start client (in no particular order)
   2. once client and server are both up, client will start making requests
   to server
   3. server goes down (for maintenance, unexpected network issues, crash)
   4. client intentionally hangs/retries the current request until the
   server is back up
   5. server comes back up
   6. client continues where it left off

What I'm currently seeing is:

   1. start server / start client (in no particular order)
   2. once client and server are both up, client will start making requests
   to server
   3. server goes down (for maintenance, unexpected network issues, crash)
   4. client throws exception / onFailure callback is called for each
   request issued while server is down
   5. server comes back up
   6. client soon reconnects to server, and requests proceed as expected

My current solution (in an effort to retry every call transparently to the
end user) is to wrap every synchronous client request (with a parallel
solution for async calls) as follows:

while (true) {
  try {
    client.request(...);
    break;
  } catch (Exception e) {
    log(e.getMessage());
  }

}

While this certainly works, I would love to implement this behavior at a
lower level, so that I don't have to individually wrap each call. Any
help/thoughts/feedback would be most appreciated!

-Walter

PS I'm using Finagle 5.3.0, Zookeeper-backed clusters, the Thrift Framed
Codec, and my client/server are written using Java.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
marius a. eriksen  
View profile  
 More options Jul 27 2012, 4:20 pm
From: "marius a. eriksen" <mar...@twitter.com>
Date: Fri, 27 Jul 2012 13:20:24 -0700
Local: Fri, Jul 27 2012 4:20 pm
Subject: Re: Finagle Retry Behavior

On Jul 27, 2012, at 11:19 AM, Walter Blaurock wrote:

You can simply specify your own retry policy. To emulate your particular example, you would simply do this (in Java-ish, since I see you are using Java):

    RetryPolicy<Try<Void>> r = new SimpleRetryPolicy<Try<Void>>() {
      public boolean shouldRetry(Try<Void> a) {
        return true;
      }

      public Duration backoffAt(int retry) {
        return Duration.fromTimeUnit(0, TimeUnit.MILLISECONDS);
      }
    };

But I highly recommend adding some sort of nonzero, growing back off, for an example of that see:

https://github.com/twitter/finagle/blob/master/finagle-core/src/test/...

marius.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Walter Blaurock  
View profile  
 More options Jul 27 2012, 6:18 pm
From: Walter Blaurock <wal...@thenextbigsound.com>
Date: Fri, 27 Jul 2012 15:18:44 -0700 (PDT)
Local: Fri, Jul 27 2012 6:18 pm
Subject: Re: Finagle Retry Behavior

Hi Marius - thanks for the reply. I have tried this in the past, but when
my server goes down, the client still throws an exception instead of
retrying. It was because of this that I reached out to find other
solutions, as I thought I was on the wrong path. The following is my
current ClientBuilder code:

                    ClientBuilder clientBuilder = ClientBuilder.get()

.codec(new ThriftClientFramedCodecFactory(Option.<ClientId> empty()))

.hostConnectionLimit(3)

.retryPolicy(new SimpleRetryPolicy<Try<Nothing$>>() {

 @Override

public Duration backoffAt(int retry) {

if (retry > 3) {

return Duration.fromTimeUnit(16, TimeUnit.SECONDS);

} else {

return Duration.fromTimeUnit((int) java.lang.Math.pow(2.0, retry), TimeUnit.
SECONDS);

}
}

 @Override

public boolean shouldRetry(Try<Nothing$> arg0) {

System.out.println("Here");

return true;

}
})

.retries(3)

.logger(logger);

And when I make calls to my client, the call in progress when the server
goes down throws something along the lines of:

Exception in thread "main" com.twitter.finagle.ChannelClosedException:
ChannelException at remote address: 10.1.1.165/10.1.1.165:34567

at com.twitter.finagle.NoStacktrace(Unknown Source)

Jul 27, 2012 5:58:08 PM
com.twitter.common.zookeeper.ServerSetImpl$ServerSetWatcher
notifyServerSetChange

WARNING: server set empty!

It was my hope that the retry policy would cause this to be attempted
repeatedly until success, as opposed to throwing an exception. I guess I'm
confused about when my retry policy comes into effect.

Thanks,

-Walter

PS I tried Void instead of Nothing$, but had trouble getting that to
compile: "The method retryPolicy(RetryPolicy<Try<Nothing$>>) in the type
ClientBuilder<ThriftClientRequest,byte[],Nothing$,ClientConfig.Yes,ClientCo nfig.Yes>
is not applicable for the arguments (RetryPolicy<Try<Void>>)"


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
marius a. eriksen  
View profile  
 More options Jul 30 2012, 12:43 pm
From: "marius a. eriksen" <mar...@twitter.com>
Date: Mon, 30 Jul 2012 09:43:45 -0700
Local: Mon, Jul 30 2012 12:43 pm
Subject: Re: Finagle Retry Behavior

The retry policy is supposed to be applied here. What does the rest of your builder look like? Are you using .build() or .buildFactory()? Can you show some more code?

Also, it looks like you’re using serverset clusters?

marius.

On Jul 27, 2012, at 3:18 PM, Walter Blaurock wrote:


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Walter Blaurock  
View profile  
 More options Jul 30 2012, 1:22 pm
From: Walter Blaurock <wal...@thenextbigsound.com>
Date: Mon, 30 Jul 2012 10:22:43 -0700 (PDT)
Local: Mon, Jul 30 2012 1:22 pm
Subject: Re: Finagle Retry Behavior

Hi Marius,

I'm building the service as follows: Service<ThriftClientRequest, byte[]>
service = ClientBuilder.safeBuild(clientBuilder);
And yes, I am use the serverset clusters with zookeeper. Below is my entire
client - thanks for the help. -Walter

package com.nextbigsound.finagle;

import java.net.InetSocketAddress;

import java.util.concurrent.TimeUnit;

import java.util.logging.Level;

import java.util.logging.Logger;

import org.apache.thrift.protocol.TBinaryProtocol;

import scala.Option;

import scala.runtime.Nothing$;

import com.nextbigsound.thrift.generated.GeoCoder;

import com.nextbigsound.thrift.generated.GeoLocation;

import com.twitter.common.quantity.Amount;

import com.twitter.common.quantity.Time;

import com.twitter.common.zookeeper.ServerSet;

import com.twitter.common.zookeeper.ServerSetImpl;

import com.twitter.common.zookeeper.ZooKeeperClient;

import com.twitter.finagle.Service;

import com.twitter.finagle.builder.ClientBuilder;

import com.twitter.finagle.service.RetryPolicy;

import com.twitter.finagle.service.SimpleRetryPolicy;

import com.twitter.finagle.thrift.ClientId;

import com.twitter.finagle.thrift.ThriftClientFramedCodecFactory;

import com.twitter.finagle.thrift.ThriftClientRequest;

import com.twitter.finagle.zookeeper.ZookeeperServerSetCluster;

import com.twitter.util.Duration;

import com.twitter.util.Future;

import com.twitter.util.Try;

/**

 * Wrapper around the GeoCoder service that exposes static methods.

 *

 * @author Walter

 *

 */

public class GeoCoderClient implements GeoCoderConfig {

 /*

 * Code below here is specific to this service. Mirror the methods found in

 * the ServiceIface interface, but make them static.

 */

 public static Future<Void> ping() {

return client.ping();

}

 public static Future<GeoLocation> forwardGeocode(String location) {

return client.forwardGeocode(location);

}

 /*

 * Code below here changes minimally between services. Please see CHANGEME

 * tasks for more info.

 */

 /**

 * The Finagle client object - all calls will ultimately go through this.

 */

private static GeoCoder.ServiceIface client; // CHANGEME - replace
"GeoCoder" with the name of the thrift class

 /**

 * Perform all initialization required to start up this service. Block until

 * service is ready.

 */

@SuppressWarnings({ "unchecked", "rawtypes" })

private static void init() {

 Logger logger = Logger.getAnonymousLogger();

logger.setLevel(Level.OFF);

 RetryPolicy<Try<Nothing$>> retryPolicy = newSimpleRetryPolicy<Try<Nothing$>>() {

 @Override

public Duration backoffAt(int retry) {

if (retry > 3) {

return Duration.fromTimeUnit(16, TimeUnit.SECONDS);

} else {

return Duration.fromTimeUnit((int) java.lang.Math.pow(2.0, retry), TimeUnit.
SECONDS);

}
}

 @Override

public boolean shouldRetry(Try<Nothing$> arg0) {

System.out.println("shouldRetry called");

return true;

}
};

 ClientBuilder clientBuilder = ClientBuilder.get()

.codec(new ThriftClientFramedCodecFactory(Option.<ClientId> empty()))

.hostConnectionLimit(3)

.retryPolicy(retryPolicy)

.retries(Integer.MAX_VALUE)

.logger(logger);

 // if we are using zookeeper to locate this service

if (ZOOKEEPER_ENABLED) {

 // get connection to the zookeeper service

System.out.printf("Connecting to zookeeper at %s:%d%n", ZOOKEEPER_HOST,
ZOOKEEPER_PORT);

ZooKeeperClient zookeeperClient = new ZooKeeperClient(Amount.of(
ZOOKEEPER_CONNECT_TIMEOUT, Time.MILLISECONDS), new InetSocketAddress(
ZOOKEEPER_HOST, ZOOKEEPER_PORT));

    ServerSet serverSet = new ServerSetImpl(zookeeperClient,
ZOOKEEPER_SERVICE_IDENTIFIER);

    ZookeeperServerSetCluster cluster = newZookeeperServerSetCluster(serverSet);

     System.out.printf("Connecting to service via Zookeeper.%n");

    clientBuilder = clientBuilder.cluster(cluster);

 }

// else use predefined address:port to connect to this service

else {

System.out.printf("Connecting to %s:%d%n", GEOCODER_HOST, GEOCODER_PORT);

clientBuilder = clientBuilder.hosts(new InetSocketAddress(GEOCODER_HOST,
GEOCODER_PORT));

}

 // build the client

Service<ThriftClientRequest, byte[]> service =
ClientBuilder.safeBuild(clientBuilder);

 // attach thrift to Finagle client

client = new GeoCoder.ServiceToClient(service, newTBinaryProtocol.Factory()); //
CHANGEME - replace "GeoCoder" with the name of the thrift class

}

 /**

 * Get it all started.

 */

static {

GeoCoderClient.init();


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
marius a. eriksen  
View profile  
 More options Aug 1 2012, 12:28 am
From: "marius a. eriksen" <mar...@twitter.com>
Date: Tue, 31 Jul 2012 21:28:10 -0700
Local: Wed, Aug 1 2012 12:28 am
Subject: Re: Finagle Retry Behavior

Oh, I see your problem (and sorry for the late reply—had a few busy days). In your client builder you have:

>                    .retryPolicy(retryPolicy)
>                    .retries(Integer.MAX_VALUE)

However “retryPolicy” overrides “retries” and vice-versa, so what you’re doing here is first setting your retry policy, and then overriding that with a default policy (which considers only WriteExceptions). Your code should work if you remove the .retries.. line.

The docs should be more clear on this..

marius.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Walter Blaurock  
View profile  
 More options Aug 1 2012, 8:26 am
From: Walter Blaurock <wal...@thenextbigsound.com>
Date: Wed, 1 Aug 2012 05:26:04 -0700 (PDT)
Local: Wed, Aug 1 2012 8:26 am
Subject: Re: Finagle Retry Behavior

Hi Marius,

That indeed fixes it. I should have realized that the functionality of
'retryPolicy' and 'retries' overlaps, which could lead to unexpected
results. But then again, everything always does seem clearer in
hindsight. Either way, I appreciate you taking the time to help me sort
this one out.

Many thanks,

-Walter


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »