Ejemplo n.º 1
0
 /// <summary>
 /// Create a proxy for an interface of implementations of that interface using
 /// the given
 /// <see cref="FailoverProxyProvider{T}"/>
 /// and the same retry policy for each
 /// method in the interface.
 /// </summary>
 /// <param name="iface">the interface that the retry will implement</param>
 /// <param name="proxyProvider">provides implementation instances whose methods should be retried
 ///     </param>
 /// <param name="retryPolicy">the policy for retrying or failing over method call failures
 ///     </param>
 /// <returns>the retry proxy</returns>
 public static object Create <T>(FailoverProxyProvider <T> proxyProvider, RetryPolicy
                                 retryPolicy)
 {
     System.Type iface = typeof(T);
     return(Proxy.NewProxyInstance(proxyProvider.GetInterface().GetClassLoader(), new
                                   Type[] { iface }, new RetryInvocationHandler <T>(proxyProvider, retryPolicy)));
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Create a proxy for an interface of implementations of that interface using
 /// the given
 /// <see cref="FailoverProxyProvider{T}"/>
 /// and the a set of retry policies
 /// specified by method name. If no retry policy is defined for a method then a
 /// default of
 /// <see cref="RetryPolicies.TryOnceThenFail"/>
 /// is used.
 /// </summary>
 /// <param name="iface">the interface that the retry will implement</param>
 /// <param name="proxyProvider">provides implementation instances whose methods should be retried
 ///     </param>
 /// <param name="methodNameToPolicyMapa">map of method names to retry policies</param>
 /// <returns>the retry proxy</returns>
 public static object Create <T>(FailoverProxyProvider <T> proxyProvider, IDictionary
                                 <string, RetryPolicy> methodNameToPolicyMap, RetryPolicy defaultPolicy)
 {
     System.Type iface = typeof(T);
     return(Proxy.NewProxyInstance(proxyProvider.GetInterface().GetClassLoader(), new
                                   Type[] { iface }, new RetryInvocationHandler <T>(proxyProvider, defaultPolicy, methodNameToPolicyMap
                                                                                    )));
 }
Ejemplo n.º 3
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++;
                        }
                    }
                }
            }
        }