Ejemplo n.º 1
0
 protected internal RetryInvocationHandler(FailoverProxyProvider <T> proxyProvider,
                                           RetryPolicy defaultPolicy, IDictionary <string, RetryPolicy> methodNameToPolicyMap
                                           )
 {
     this.proxyProvider         = proxyProvider;
     this.defaultPolicy         = defaultPolicy;
     this.methodNameToPolicyMap = methodNameToPolicyMap;
     this.currentProxy          = proxyProvider.GetProxy();
 }
Ejemplo n.º 2
0
        /// <exception cref="System.Exception"/>
        public virtual object Invoke(object proxy, MethodInfo method, object[] args)
        {
            RetryPolicy policy = methodNameToPolicyMap[method.Name];

            if (policy == null)
            {
                policy = defaultPolicy;
            }
            // The number of times this method invocation has been failed over.
            int  invocationFailoverCount = 0;
            bool isRpc   = IsRpcInvocation(currentProxy.proxy);
            int  callId  = isRpc ? Client.NextCallId() : RpcConstants.InvalidCallId;
            int  retries = 0;

            while (true)
            {
                // The number of times this invocation handler has ever been failed over,
                // before this method invocation attempt. Used to prevent concurrent
                // failed method invocations from triggering multiple failover attempts.
                long invocationAttemptFailoverCount;
                lock (proxyProvider)
                {
                    invocationAttemptFailoverCount = proxyProviderFailoverCount;
                }
                if (isRpc)
                {
                    Client.SetCallIdAndRetryCount(callId, retries);
                }
                try
                {
                    object ret = InvokeMethod(method, args);
                    hasMadeASuccessfulCall = true;
                    return(ret);
                }
                catch (Exception e)
                {
                    if (Thread.CurrentThread().IsInterrupted())
                    {
                        // If interrupted, do not retry.
                        throw;
                    }
                    bool isIdempotentOrAtMostOnce = proxyProvider.GetInterface().GetMethod(method.Name
                                                                                           , Runtime.GetParameterTypes(method)).IsAnnotationPresent(typeof(Idempotent
                                                                                                                                                           ));
                    if (!isIdempotentOrAtMostOnce)
                    {
                        isIdempotentOrAtMostOnce = proxyProvider.GetInterface().GetMethod(method.Name, Runtime.GetParameterTypes
                                                                                              (method)).IsAnnotationPresent(typeof(AtMostOnce));
                    }
                    RetryPolicy.RetryAction action = policy.ShouldRetry(e, retries++, invocationFailoverCount
                                                                        , isIdempotentOrAtMostOnce);
                    if (action.action == RetryPolicy.RetryAction.RetryDecision.Fail)
                    {
                        if (action.reason != null)
                        {
                            Log.Warn("Exception while invoking " + currentProxy.proxy.GetType() + "." + method
                                     .Name + " over " + currentProxy.proxyInfo + ". Not retrying because " + action.reason
                                     , e);
                        }
                        throw;
                    }
                    else
                    {
                        // retry or failover
                        // avoid logging the failover if this is the first call on this
                        // proxy object, and we successfully achieve the failover without
                        // any flip-flopping
                        bool worthLogging = !(invocationFailoverCount == 0 && !hasMadeASuccessfulCall);
                        worthLogging |= Log.IsDebugEnabled();
                        if (action.action == RetryPolicy.RetryAction.RetryDecision.FailoverAndRetry && worthLogging)
                        {
                            string msg = "Exception while invoking " + method.Name + " of class " + currentProxy
                                         .proxy.GetType().Name + " over " + currentProxy.proxyInfo;
                            if (invocationFailoverCount > 0)
                            {
                                msg += " after " + invocationFailoverCount + " fail over attempts";
                            }
                            msg += ". Trying to fail over " + FormatSleepMessage(action.delayMillis);
                            Log.Info(msg, e);
                        }
                        else
                        {
                            if (Log.IsDebugEnabled())
                            {
                                Log.Debug("Exception while invoking " + method.Name + " of class " + currentProxy
                                          .proxy.GetType().Name + " over " + currentProxy.proxyInfo + ". Retrying " + FormatSleepMessage
                                              (action.delayMillis), e);
                            }
                        }
                        if (action.delayMillis > 0)
                        {
                            Thread.Sleep(action.delayMillis);
                        }
                        if (action.action == RetryPolicy.RetryAction.RetryDecision.FailoverAndRetry)
                        {
                            // Make sure that concurrent failed method invocations only cause a
                            // single actual fail over.
                            lock (proxyProvider)
                            {
                                if (invocationAttemptFailoverCount == proxyProviderFailoverCount)
                                {
                                    proxyProvider.PerformFailover(currentProxy.proxy);
                                    proxyProviderFailoverCount++;
                                }
                                else
                                {
                                    Log.Warn("A failover has occurred since the start of this method" + " invocation attempt."
                                             );
                                }
                                currentProxy = proxyProvider.GetProxy();
                            }
                            invocationFailoverCount++;
                        }
                    }
                }
            }
        }