All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nirvana.support.services.ZkClientSupport.scala Maven / Gradle / Ivy

// Copyright 2014 Jun Tsai. All rights reserved.
// site: http://www.ganshane.com
package nirvana.support.services

import org.apache.curator.framework.{CuratorFrameworkFactory, CuratorFramework}
import org.apache.curator.retry.RetryNTimes
import org.apache.curator.framework.state.{ConnectionState, ConnectionStateListener}
import org.apache.tapestry5.ioc.services.cron.{IntervalSchedule, PeriodicExecutor}
import java.util.concurrent.locks.ReentrantLock

/**
 * zookeeper的客户端
 */
trait ZkClientSupport extends ServiceLifecycle with ServiceWaitingInitSupport {
  this:ZookeeperTemplate =>

  sealed class WatchMode;
  case object OnceWatch extends WatchMode
  case object PermanentWatch extends WatchMode

  private var client:Option[CuratorFramework] = None
  private final val lock = new ReentrantLock()
  /**
   * 得到Zookeeper的客户端
   * @return zookeeper client
   */
  def zkClient: CuratorFramework = {
    awaitServiceInit()
    client.getOrElse {
      throw new NirvanaException("zk client not be initialized", NirvanaSupportErrorCode.ZK_NOT_BE_INITIALIZED)
    }
  }
  /**
   * 启动对象实例
   */

  def start() {
    throwExceptionIfServiceInitialized()

    val builder = CuratorFrameworkFactory.builder()
      .connectString(address)
      .retryPolicy(new RetryNTimes(Integer.MAX_VALUE, 1000))
      .connectionTimeoutMs(sessionTimeout).
      defaultData(null)
    if (basePath.isDefined) {
      if(basePath.get.charAt(0) == '/'){
        //curator中的namespace前端没有 / 开头
        builder.namespace(basePath.get.substring(1))
      }else{
        builder.namespace(basePath.get)
      }
    }

    val tmpClient = builder.build();
    //增加统一的状态监听,方便对watcher进行再次监控
    tmpClient.getConnectionStateListenable.addListener(new ConnectionStateListener() {
      def stateChanged(client:CuratorFramework, state:ConnectionState) {
        try {
          //不支持多线程进行watch,避免过多的watch
          lock.lock()
          doStateChanged(state)
        }finally {
          lock.unlock()
        }
      }
    })
    tmpClient.start()

    client = Some(tmpClient)

    serviceInitialized()
  }

  /**
   * 启动对异常数据的检测,实现FailBack功能
   * @param periodExecutor 定时执行器
   */
  def startCheckFailed(periodExecutor:PeriodicExecutor){
    if(periodExecutor == null) {
      logger.error("periodExecutor is null!")
      return
    }
    //启动定时器
    periodExecutor.addJob(new IntervalSchedule(1L * 60 * 1000),"check-zk",new Runnable {
      def run() {
        retry()
      }
    })
  }

  /**
   * 关闭对象
   */
  def shutdown() {
    logger.debug("closing zk client....")
    client.foreach(_.close)
  }
  private def doStateChanged(state:ConnectionState){
    if(state == ConnectionState.CONNECTED){ //第一次连接
      //connectedFun.apply(this)
    }else if(state == ConnectionState.RECONNECTED){ //重新连接上,通常是session过期造成的
      logger.info("cloud server reconnected")
      //针对临时节点的再次创建
      recreateEphemeralNodes

      rewatchNodeData
      rewatchChildren

      //connectedFun.apply(this)
    }
  }
  //尝试修正失败的数据
  private[nirvana] def retry(){
    retryFailedEphemeralNodes()
    retryFailedWatchNodeData()
    retryFailedChildrenWatcher()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy