0

We are working with couchbase for more than a year and want to improve our work with their .Net sdk.

In their website i could not find the recommendation for the best way to use get/set.

I know that when i am trying to use : CouchbaseClient.Get(key) it can fail, and than we should wait for X time and try again.

I want to understand what is the best practice for the waiting times when doing a get/set process.

Can anyone who encounter this issue advise me about it please?

FelProNet
  • 689
  • 2
  • 10
  • 25

3 Answers3

2

I haven't used the .net client as I only work with Java and Ruby with Couchbase but the high level concepts are going to be the same.

You say that the get operation can fail, do you find it fails a lot? You have to handle several exceptions, operation timeout when the smart client fails to communicate in a timely manner with the cluster or the queue is too full to accept new requests (meant to be very rare).

You should wrap your calls (get/set/add) and catch the particular exception and then it all depends on what the requirements of your system are. If you are reaching a full queue retrying requests multiple times is going to make the situation worse. Is there not a default you can return in the case of an exception?

In our application (REST API) if we catch a timeout issue then we throw a custom exception which we return to the user notifying them to retry in the future.

IF we had the business requirement that we had to retry then we'd need to catch the timeout and either place the request onto a queue or invoke a specific retry strategy.

If you are catching either exception then it could be a sign that your system is or is about to go down, so monitor it carefully. I think this page from the Couchbase documentation covers the issues quite well.

https://www.couchbase.com/docs/couchbase-devguide-2.0/about-client-timeouts.html

And documentation on the C# specific sdk http://www.couchbase.com/docs/couchbase-sdk-net-1.2/couchbase-sdk-net-configuration.html

I hope this helps, if not feel free to expand on your original question with more details.

scalabilitysolved
  • 2,473
  • 1
  • 26
  • 31
  • It helps a little. I did not find the first link you posted so it is a good stuff to read. But i want to ask you something else, If you want to execute a get operation in your app, and you get an error , do you try for a couple of time again with a sleep between them (millisec or seconds)? – FelProNet Feb 05 '14 at 21:05
  • No a) because of our requirements don't ask for that. (see above) and b) What if you are catching a queue full exception? You'll end up putting even more load on a potentially failing node/cluster. If you have don't have to reply immediately just pop the payload onto a queue or something and let your service retry when you can verify the cluster is healthy. You really shouldn't be seeing many errors on operations. – scalabilitysolved Feb 05 '14 at 21:58
2

In general, I suggest you use the ExecuteXXX where XXX is an operation methods as opposed to the regular/legacy Get or Set methods. The reason is that these methods return additional information about the operation and this info can be used to tailor your retry strategy.

For more information, read this portion of the documentation: http://docs.couchbase.com/couchbase-sdk-net-1.3/#working-with-operation-results-and-error-codes

jeffrymorris
  • 464
  • 3
  • 3
  • What are the performance effects of using ExecuteXXX instead of XXX? In the couchbase docs which i read..there are not information or samples on how to handle some of the error code..for example: when should i wait and try to XXX again? how many times should i do it? – FelProNet Feb 08 '14 at 16:17
  • 1
    For performance effects, pretty much nothing; we simply return an object with information that is already available from the server and client. – jeffrymorris Feb 08 '14 at 18:19
  • Thanks Jeff. Do you have answers for the other questions i asked after the performance? – FelProNet Feb 09 '14 at 06:50
  • It depends on the StatusCode value: http://docs.couchbase.com/couchbase-sdk-net-1.3/#checking-error-codes – jeffrymorris Feb 10 '14 at 17:56
  • 1
    If you go through the list above, the one's in which a retry attempt are warranted are stated there. Most retries are for very temporary cluster/client state in failover/rebalance scenarios. Some, such as VBucketBelongsToAnotherServer and NodeShutdown will cause the client to retry internally. As a rule, no delay is necessary (accept for perhaps a few milliseconds), but you don't want to DNS the server (so put a hard limit on retries 2, 3, 5). One way to handle this is an exponential back-off strategy. – jeffrymorris Feb 10 '14 at 18:04
  • Thanks again Jeff, you help a lot. Do you have an example code of an infrastructure working with CouchbaseClient as you described here with exponential back-off? (prefer .Net but can be other language) – FelProNet Feb 11 '14 at 08:13
0

Thanks for the answers here.

By those answers and good post i found in this forum: Retry process

I wrote some code and here is an example for one of its methods:

            public static TResult Do<T,TResult>(Func<T,TResult> action, T param, TimeSpan retryInterval, int retryCount = 3)
            {
                for (int retry = 0; retry < retryCount; retry++)
                {
                    try
                    {
                        return action(param);
                    }
                    catch (RetryOperationException)
                    {
                        Log.SaveFormat("Retry:{0} for action:{1}", "RetryProcessLog",retry, action.Method.Name);
                        Thread.Sleep(retryInterval);
                    }
                    catch (Exception ex)
                    {
                        Log.SaveFormat("Exception when retry:{0} error:{1}","RetryProcessLog",action.Method.Name,ex.Message);
                        return default(TResult);
                    }
                }

                return default(TResult);
            }

        public static T ExecuteGet<T>(string key)
        {
            var defaultReturnValue = default(T);

            cacheHit("ExecuteGet", key);

            var result = CacheClient.ExecuteGet<T>(CachePrefix + key);

            if (result.Success)
            {
                return result.Value;
            }
            else if (result.StatusCode ==
                     CouchbaseStatusCode.StatusCodeExtension.ToInt(CouchbaseStatusCode.StatusCode.Busy)
                     ||
                     result.StatusCode ==
                     CouchbaseStatusCode.StatusCodeExtension.ToInt(CouchbaseStatusCode.StatusCode.TemporaryFailure)
                     ||
                     result.StatusCode ==
                     CouchbaseStatusCode.StatusCodeExtension.ToInt(CouchbaseStatusCode.StatusCode.SocketPoolTimeout)
                     ||
                     result.StatusCode ==
                     CouchbaseStatusCode.StatusCodeExtension.ToInt(CouchbaseStatusCode.StatusCode.UnableToLocateNode)
                     ||
                     result.StatusCode ==
                     CouchbaseStatusCode.StatusCodeExtension.ToInt(CouchbaseStatusCode.StatusCode.NodeShutdown)
                     ||
                     result.StatusCode ==
                     CouchbaseStatusCode.StatusCodeExtension.ToInt(CouchbaseStatusCode.StatusCode.OperationTimeout))
            {
                Log.SaveFormat("Error:{0}:{2} in ExecuteGet for key:{1}. Going to throw RetryOperationException",
                               "CacheManager", result.StatusCode, key,result.Message);
                throw new RetryOperationException();
            }

            Log.SaveFormat("Error:{0}:{2} in ExecuteGet for key:{1}", "CacheManager", result.StatusCode, key,result.Message);
            return defaultReturnValue;
        }

This is just an example and you can add more method overloads that gets more than one param or other method without a return value. The second method is in different class and uses the ExecuteGet.

And here is an example of usage:

var result = RetryProcess.Do(CacheManager.ExecuteGet<long>, keyOfValue, TimeSpan.FromMilliseconds(10));

Hope it helps.

Community
  • 1
  • 1
FelProNet
  • 689
  • 2
  • 10
  • 25