Spring-Cloud-Ribbon-IRule-RetryRule

package com.netflix.loadbalancer;

import com.netflix.client.config.IClientConfig;

/**
 * Given that
 * {@link IRule} can be cascaded, this {@link RetryRule} class allows adding a retry logic to an existing Rule.
 * 
 * @author stonse
 * 
 */
public class RetryRule extends AbstractLoadBalancerRule {
   IRule subRule = new RoundRobinRule();
   long maxRetryMillis = 500;

   public RetryRule() {
   }

   public RetryRule(IRule subRule) {
      this.subRule = (subRule != null) ? subRule : new RoundRobinRule();
   }

   public RetryRule(IRule subRule, long maxRetryMillis) {
      this.subRule = (subRule != null) ? subRule : new RoundRobinRule();
      this.maxRetryMillis = (maxRetryMillis > 0) ? maxRetryMillis : 500;
   }

   public void setRule(IRule subRule) {
      this.subRule = (subRule != null) ? subRule : new RoundRobinRule();
   }

   public IRule getRule() {
      return subRule;
   }

   public void setMaxRetryMillis(long maxRetryMillis) {
      if (maxRetryMillis > 0) {
         this.maxRetryMillis = maxRetryMillis;
      } else {
         this.maxRetryMillis = 500;
      }
   }

   public long getMaxRetryMillis() {
      return maxRetryMillis;
   }

   
   
   @Override
   public void setLoadBalancer(ILoadBalancer lb) {       
      super.setLoadBalancer(lb);
      subRule.setLoadBalancer(lb);
   }

   /*
    * Loop if necessary. Note that the time CAN be exceeded depending on the
    * subRule, because we're not spawning additional threads and returning
    * early.
    */
   public Server choose(ILoadBalancer lb, Object key) {
      long requestTime = System.currentTimeMillis();
      long deadline = requestTime + maxRetryMillis;

      Server answer = null;

      answer = subRule.choose(key);

      if (((answer == null) || (!answer.isAlive()))
            && (System.currentTimeMillis() < deadline)) {

         // 這裏定義了一個InterruptTask,繼承TimerTask;
         // 而且實現了抽象的run方法,run方法的實現很簡單,就是判斷,若是InterruptTask裏面構建的當前線程不爲null而且還活着,就中斷該線程;
         // 這個InterruptTask裏面實現的run方法何時執行呢,就是在當前時間+maxRetryMillis時執行,中斷當前線程,這個run方法是在Timer裏的mainloop裏task.run()調用的
         InterruptTask task = new InterruptTask(deadline
               - System.currentTimeMillis());

         // 這裏判斷Thread.interrupted(),就是和上面InterruptTask的run方法呼應上了,在當前時間+maxRetryMillis以前,這個while爲true,從而在當前時間到當前時間+maxRetryMillis這個時間段內,反覆重試獲取server
         while (!Thread.interrupted()) {
            answer = subRule.choose(key);

            if (((answer == null) || (!answer.isAlive()))
                  && (System.currentTimeMillis() < deadline)) {
               /* pause and retry hoping it's transient */
               Thread.yield();
            } else {
               break;
            }
         }
     // 最終要把這個InterruptTask取消掉,這樣就能把Timer.TimerQueue中對於該task的引用移除
         task.cancel();
      }

      if ((answer == null) || (!answer.isAlive())) {
         return null;
      } else {
         return answer;
      }
   }

   @Override
   public Server choose(Object key) {
      return choose(getLoadBalancer(), key);
   }

   @Override
   public void initWithNiwsConfig(IClientConfig clientConfig) {
   }
}
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息