Coverage Report - com.ctrip.apollo.portal.PortalSettings
 
Classes in this File Line Coverage Branch Coverage Complexity
PortalSettings
65%
15/23
50%
4/8
2.571
PortalSettings$HealthCheckTask
74%
23/31
58%
7/12
2.571
 
 1  
 package com.ctrip.apollo.portal;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.HashMap;
 5  
 import java.util.LinkedList;
 6  
 import java.util.List;
 7  
 import java.util.Map;
 8  
 import java.util.concurrent.ConcurrentHashMap;
 9  
 import java.util.concurrent.Executors;
 10  
 import java.util.concurrent.ScheduledExecutorService;
 11  
 import java.util.concurrent.TimeUnit;
 12  
 
 13  
 import javax.annotation.PostConstruct;
 14  
 
 15  
 import org.slf4j.Logger;
 16  
 import org.slf4j.LoggerFactory;
 17  
 import org.springframework.beans.factory.annotation.Autowired;
 18  
 import org.springframework.beans.factory.annotation.Value;
 19  
 import org.springframework.boot.actuate.health.Health;
 20  
 import org.springframework.context.ApplicationContext;
 21  
 import org.springframework.stereotype.Component;
 22  
 
 23  
 import com.ctrip.apollo.core.enums.Env;
 24  
 import com.ctrip.apollo.portal.api.AdminServiceAPI;
 25  
 
 26  
 @Component
 27  11
 public class PortalSettings {
 28  
 
 29  1
   private Logger logger = LoggerFactory.getLogger(PortalSettings.class);
 30  
 
 31  
   private static final int HEALTH_CHECK_INTERVAL = 5000;
 32  
 
 33  
   @Value("#{'${apollo.portal.env}'.split(',')}")
 34  
   private List<String> allStrEnvs;
 35  
 
 36  
   @Autowired
 37  
   ApplicationContext applicationContext;
 38  
 
 39  1
   private List<Env> allEnvs = new ArrayList<Env>();
 40  
 
 41  
   private List<Env> activeEnvs;
 42  
 
 43  
   //mark env up or down
 44  1
   private Map<Env, Boolean> envStatusMark = new ConcurrentHashMap<>();
 45  
 
 46  
   private ScheduledExecutorService healthCheckService;
 47  
 
 48  
   @PostConstruct
 49  
   private void postConstruct() {
 50  
     //init origin config envs
 51  1
     for (String e : allStrEnvs) {
 52  1
       allEnvs.add(Env.valueOf(e.toUpperCase()));
 53  1
     }
 54  
 
 55  1
     for (Env env : allEnvs) {
 56  1
       envStatusMark.put(env, true);
 57  1
     }
 58  
 
 59  1
     healthCheckService = Executors.newScheduledThreadPool(1);
 60  
 
 61  1
     healthCheckService
 62  1
         .scheduleWithFixedDelay(new HealthCheckTask(applicationContext), 1000, HEALTH_CHECK_INTERVAL,
 63  
                                 TimeUnit.MILLISECONDS);
 64  
 
 65  1
   }
 66  
 
 67  
   public List<Env> getActiveEnvs() {
 68  0
     List<Env> activeEnvs = new LinkedList<>();
 69  0
     for (Env env : allEnvs) {
 70  0
       if (envStatusMark.get(env)) {
 71  0
         activeEnvs.add(env);
 72  
       }
 73  0
     }
 74  0
     this.activeEnvs = activeEnvs;
 75  0
     return activeEnvs;
 76  
   }
 77  
 
 78  
   public Env getFirstAliveEnv() {
 79  0
     return activeEnvs.get(0);
 80  
   }
 81  
 
 82  
 
 83  1
   class HealthCheckTask implements Runnable {
 84  
 
 85  
     private static final int ENV_DIED_THREADHOLD = 2;
 86  
 
 87  1
     private Map<Env, Long> healthCheckFailCnt = new HashMap<>();
 88  
 
 89  
     private AdminServiceAPI.HealthAPI healthAPI;
 90  
 
 91  1
     public HealthCheckTask(ApplicationContext context) {
 92  1
       healthAPI = context.getBean(AdminServiceAPI.HealthAPI.class);
 93  1
       for (Env env : allEnvs) {
 94  1
         healthCheckFailCnt.put(env, 0l);
 95  1
       }
 96  1
     }
 97  
 
 98  
     public void run() {
 99  
 
 100  2
       for (Env env : allEnvs) {
 101  
         try {
 102  2
           if (isUp(env)) {
 103  
             //revive
 104  0
             if (!envStatusMark.get(env)) {
 105  0
               envStatusMark.put(env, true);
 106  0
               healthCheckFailCnt.put(env, 0l);
 107  0
               logger.info("env up again [env:{}]", env);
 108  
             }
 109  
           } else {
 110  
             //maybe meta server up but admin server down
 111  0
             handleEnvDown(env);
 112  
           }
 113  
 
 114  2
         } catch (Exception e) {
 115  
           //maybe meta server down
 116  2
           logger.warn("health check fail. [env:{}]", env, e.getMessage());
 117  2
           handleEnvDown(env);
 118  0
         }
 119  2
       }
 120  
 
 121  2
     }
 122  
 
 123  
     private boolean isUp(Env env) {
 124  2
       Health health = healthAPI.health(env);
 125  0
       return "UP".equals(health.getStatus().getCode());
 126  
     }
 127  
 
 128  
     private void handleEnvDown(Env env) {
 129  2
       long failCnt = healthCheckFailCnt.get(env);
 130  2
       healthCheckFailCnt.put(env, ++failCnt);
 131  
 
 132  2
       if (!envStatusMark.get(env)) {
 133  0
         logger.warn("[env:{}] down yet.", env);
 134  
       } else {
 135  2
         if (failCnt >= ENV_DIED_THREADHOLD) {
 136  1
           envStatusMark.put(env, false);
 137  1
           logger.error("env turn to down [env:{}]", env);
 138  
         } else {
 139  1
           logger.warn("env health check fail first time. [env:{}]", env);
 140  
         }
 141  
       }
 142  
 
 143  2
     }
 144  
 
 145  
   }
 146  
 }