private void deferExpired() {
   for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) {
     JedisPool jedisPool = entry.getValue();
     try {
       Jedis jedis = jedisPool.getResource();
       try {
         for (Node node : new HashSet<Node>(getRegistered())) {
           String key = NodeRegistryUtils.getNodeTypePath(clusterName, node.getNodeType());
           if (jedis.hset(
                   key, node.toFullString(), String.valueOf(SystemClock.now() + expirePeriod))
               == 1) {
             jedis.publish(key, Constants.REGISTER);
           }
         }
         if (lock.acquire(jedis)) {
           clean(jedis);
         }
         if (!replicate) {
           break; //  如果服务器端已同步数据,只需写入单台机器
         }
       } finally {
         jedis.close();
       }
     } catch (Throwable t) {
       LOGGER.warn(
           "Failed to write provider heartbeat to redis registry. registry: "
               + entry.getKey()
               + ", cause: "
               + t.getMessage(),
           t);
     }
   }
 }
 private void clean(Jedis jedis) {
   // /LTS/{集群名字}/NODES/
   Set<String> nodeTypePaths =
       jedis.keys(NodeRegistryUtils.getRootPath(appContext.getConfig().getClusterName()) + "/*");
   if (CollectionUtils.isNotEmpty(nodeTypePaths)) {
     for (String nodeTypePath : nodeTypePaths) {
       // /LTS/{集群名字}/NODES/JOB_TRACKER
       Set<String> nodePaths = jedis.keys(nodeTypePath);
       if (CollectionUtils.isNotEmpty(nodePaths)) {
         for (String nodePath : nodePaths) {
           Map<String, String> nodes = jedis.hgetAll(nodePath);
           if (CollectionUtils.isNotEmpty(nodes)) {
             boolean delete = false;
             long now = SystemClock.now();
             for (Map.Entry<String, String> entry : nodes.entrySet()) {
               String key = entry.getKey();
               long expire = Long.parseLong(entry.getValue());
               if (expire < now) {
                 jedis.hdel(nodePath, key);
                 delete = true;
                 if (LOGGER.isWarnEnabled()) {
                   LOGGER.warn(
                       "Delete expired key: "
                           + nodePath
                           + " -> value: "
                           + entry.getKey()
                           + ", expire: "
                           + new Date(expire)
                           + ", now: "
                           + new Date(now));
                 }
               }
             }
             if (delete) {
               jedis.publish(nodePath, Constants.UNREGISTER);
             }
           }
         }
       }
     }
   }
 }
 @Override
 protected void doRegister(Node node) {
   String key = NodeRegistryUtils.getNodeTypePath(clusterName, node.getNodeType());
   String expire = String.valueOf(SystemClock.now() + expirePeriod);
   boolean success = false;
   NodeRegistryException exception = null;
   for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) {
     JedisPool jedisPool = entry.getValue();
     try {
       Jedis jedis = jedisPool.getResource();
       try {
         jedis.hset(key, node.toFullString(), expire);
         jedis.publish(key, Constants.REGISTER);
         success = true;
         if (!replicate) {
           break; //  如果服务器端已同步数据,只需写入单台机器
         }
       } finally {
         jedis.close();
       }
     } catch (Throwable t) {
       exception =
           new NodeRegistryException(
               "Failed to register node to redis registry. registry: "
                   + entry.getKey()
                   + ", node: "
                   + node
                   + ", cause: "
                   + t.getMessage(),
               t);
     }
   }
   if (exception != null) {
     if (success) {
       LOGGER.warn(exception.getMessage(), exception);
     } else {
       throw exception;
     }
   }
 }
 public boolean isTimeout() {
   long diff = SystemClock.now() - this.beginTimestamp;
   return diff > this.timeoutMillis;
 }
/** 异步请求应答封装 */
public class ResponseFuture {
  private final int opaque;
  private final long timeoutMillis;
  private final AsyncCallback asyncCallback;
  private final long beginTimestamp = SystemClock.now();
  private final CountDownLatch countDownLatch = new CountDownLatch(1);
  // 保证信号量至多至少只被释放一次
  private final SemaphoreReleaseOnlyOnce once;
  // 保证回调的callback方法至多至少只被执行一次
  private final AtomicBoolean executeCallbackOnlyOnce = new AtomicBoolean(false);
  private volatile RemotingCommand responseCommand;
  private volatile boolean sendRequestOK = true;
  private volatile Throwable cause;

  public ResponseFuture(
      int opaque, long timeoutMillis, AsyncCallback asyncCallback, SemaphoreReleaseOnlyOnce once) {
    this.opaque = opaque;
    this.timeoutMillis = timeoutMillis;
    this.asyncCallback = asyncCallback;
    this.once = once;
  }

  public void executeInvokeCallback() {
    if (asyncCallback != null) {
      if (this.executeCallbackOnlyOnce.compareAndSet(false, true)) {
        asyncCallback.operationComplete(this);
      }
    }
  }

  public void release() {
    if (this.once != null) {
      this.once.release();
    }
  }

  public boolean isTimeout() {
    long diff = SystemClock.now() - this.beginTimestamp;
    return diff > this.timeoutMillis;
  }

  public RemotingCommand waitResponse(final long timeoutMillis) throws InterruptedException {
    this.countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
    return this.responseCommand;
  }

  public void putResponse(final RemotingCommand responseCommand) {
    this.responseCommand = responseCommand;
    this.countDownLatch.countDown();
  }

  public long getBeginTimestamp() {
    return beginTimestamp;
  }

  public boolean isSendRequestOK() {
    return sendRequestOK;
  }

  public void setSendRequestOK(boolean sendRequestOK) {
    this.sendRequestOK = sendRequestOK;
  }

  public long getTimeoutMillis() {
    return timeoutMillis;
  }

  public AsyncCallback getAsyncCallback() {
    return asyncCallback;
  }

  public Throwable getCause() {
    return cause;
  }

  public void setCause(Throwable cause) {
    this.cause = cause;
  }

  public RemotingCommand getResponseCommand() {
    return responseCommand;
  }

  public void setResponseCommand(RemotingCommand responseCommand) {
    this.responseCommand = responseCommand;
  }

  public int getOpaque() {
    return opaque;
  }

  @Override
  public String toString() {
    return "ResponseFuture [responseCommand="
        + responseCommand
        + ", sendRequestOK="
        + sendRequestOK
        + ", cause="
        + cause
        + ", opaque="
        + opaque
        + ", timeoutMillis="
        + timeoutMillis
        + ", invokeCallback="
        + asyncCallback
        + ", beginTimestamp="
        + beginTimestamp
        + ", countDownLatch="
        + countDownLatch
        + "]";
  }
}