/** @author Robert HG ([email protected]) on 8/19/14. */
public class TestJobRunner implements JobRunner {

  private static final Logger LOGGER = LoggerFactory.getLogger(TestJobRunner.class);
  private static final BizLogger bizLogger = LtsLoggerFactory.getBizLogger();

  @Override
  public Result run(Job job) throws Throwable {
    try {
      //            Thread.sleep(1000L);
      //
      //            if (job.getRetryTimes() > 5) {
      //                return new Result(Action.EXECUTE_FAILED, "重试次数超过5次了,放过你吧!");
      //            }
      //
      //            if (SystemClock.now() % 2 == 1) {
      //                return new Result(Action.EXECUTE_LATER, "稍后执行");
      //            }

      // TODO 业务逻辑
      LOGGER.info("我要执行:" + job);
      // 会发送到 LTS (JobTracker上)
      bizLogger.info("测试,业务日志啊啊啊啊啊");

    } catch (Exception e) {
      LOGGER.info("Run job failed!", e);
      return new Result(Action.EXECUTE_FAILED, e.getMessage());
    }
    return new Result(Action.EXECUTE_SUCCESS, "执行成功了,哈哈");
  }
}
  /**
   * Create a new NoopFilter using a name
   *
   * @param name the name used to create the logger. If null, will default to "NoopFilter"
   */
  public MinaLogger(String name) {
    if (name == null) {
      this.name = MinaLogger.class.getName();
    } else {
      this.name = name;
    }

    logger = LoggerFactory.getLogger(this.name);
  }
/** @author Robert HG ([email protected]) on 11/19/15. */
public class JSONFactory {

  private static final Logger LOGGER = LoggerFactory.getLogger(JSONFactory.class);

  private static volatile JSONAdapter JSON_ADAPTER;

  static {
    String json = System.getProperty("lts.json");
    if ("fastjson".equals(json)) {
      setJSONAdapter(new FastJSONAdapter());
    } else if ("jackson".equals(json)) {
      setJSONAdapter(new JacksonJSONAdapter());
    } else {
      try {
        setJSONAdapter(new FastJSONAdapter());
      } catch (Throwable ignored) {
        try {
          setJSONAdapter(new JacksonJSONAdapter());
        } catch (Throwable ignored2) {
          try {
            setJSONAdapter(new LtsJSONAdapter());
          } catch (Throwable ignored3) {
            throw new JSONException("Please check JSON lib");
          }
        }
      }
    }
  }

  public static void setJSONAdapter(String jsonAdapter) {
    if (StringUtils.isNotEmpty(jsonAdapter)) {
      setJSONAdapter(ServiceLoader.load(JSONAdapter.class, jsonAdapter));
    }
  }

  public static JSONAdapter getJSONAdapter() {
    return JSONFactory.JSON_ADAPTER;
  }

  public static void setJSONAdapter(JSONAdapter jsonAdapter) {
    if (jsonAdapter != null) {
      LOGGER.info("Using JSON lib " + jsonAdapter.getName());
      JSONFactory.JSON_ADAPTER = jsonAdapter;
    }
  }
}
/** @author Robert HG ([email protected]) on 11/3/15. */
public class NettyRemotingClient extends AbstractRemotingClient {
  private static final Logger LOGGER = LoggerFactory.getLogger(RemotingHelper.RemotingLogName);

  private final Bootstrap bootstrap = new Bootstrap();
  private final EventLoopGroup eventLoopGroup;
  private DefaultEventExecutorGroup defaultEventExecutorGroup;

  public NettyRemotingClient(final RemotingClientConfig remotingClientConfig) {
    this(remotingClientConfig, null);
  }

  public NettyRemotingClient(
      final RemotingClientConfig remotingClientConfig,
      final ChannelEventListener channelEventListener) {
    super(remotingClientConfig, channelEventListener);

    this.eventLoopGroup = new NioEventLoopGroup(remotingClientConfig.getClientSelectorThreads());
  }

  @Override
  protected void clientStart() throws RemotingException {

    NettyLogger.setNettyLoggerFactory();

    this.defaultEventExecutorGroup =
        new DefaultEventExecutorGroup(
            remotingClientConfig.getClientWorkerThreads(),
            new NamedThreadFactory("NettyClientWorkerThread_"));

    final NettyCodecFactory nettyCodecFactory = new NettyCodecFactory(getCodec());

    this.bootstrap
        .group(this.eventLoopGroup)
        .channel(NioSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
        .handler(
            new ChannelInitializer<SocketChannel>() {
              @Override
              public void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline()
                    .addLast( //
                        defaultEventExecutorGroup, //
                        nettyCodecFactory.getEncoder(), //
                        nettyCodecFactory.getDecoder(), //
                        new IdleStateHandler(
                            remotingClientConfig.getReaderIdleTimeSeconds(),
                            remotingClientConfig.getWriterIdleTimeSeconds(),
                            remotingClientConfig.getClientChannelMaxIdleTimeSeconds()), //
                        new NettyConnectManageHandler(), //
                        new NettyClientHandler());
              }
            });
  }

  @Override
  protected void clientShutdown() {

    this.eventLoopGroup.shutdownGracefully();

    if (this.defaultEventExecutorGroup != null) {
      this.defaultEventExecutorGroup.shutdownGracefully();
    }
  }

  @Override
  protected com.lts.remoting.ChannelFuture connect(SocketAddress socketAddress) {
    ChannelFuture channelFuture = this.bootstrap.connect(socketAddress);
    return new com.lts.remoting.netty.NettyChannelFuture(channelFuture);
  }

  class NettyClientHandler extends SimpleChannelInboundHandler<RemotingCommand> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
      processMessageReceived(new NettyChannel(ctx), msg);
    }
  }

  class NettyConnectManageHandler extends ChannelDuplexHandler {
    @Override
    public void connect(
        ChannelHandlerContext ctx,
        SocketAddress remoteAddress,
        SocketAddress localAddress,
        ChannelPromise promise)
        throws Exception {
      final String local = localAddress == null ? "UNKNOW" : localAddress.toString();
      final String remote = remoteAddress == null ? "UNKNOW" : remoteAddress.toString();
      LOGGER.info("CLIENT : CONNECT  {} => {}", local, remote);
      super.connect(ctx, remoteAddress, localAddress, promise);

      if (channelEventListener != null) {
        assert remoteAddress != null;
        putRemotingEvent(
            new RemotingEvent(
                RemotingEventType.CONNECT, remoteAddress.toString(), new NettyChannel(ctx)));
      }
    }

    @Override
    public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {

      Channel channel = new NettyChannel(ctx);

      final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(channel);
      LOGGER.info("CLIENT : DISCONNECT {}", remoteAddress);
      closeChannel(channel);
      super.disconnect(ctx, promise);

      if (channelEventListener != null) {
        putRemotingEvent(new RemotingEvent(RemotingEventType.CLOSE, remoteAddress, channel));
      }
    }

    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
      Channel channel = new NettyChannel(ctx);

      final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(channel);
      LOGGER.info("CLIENT : CLOSE {}", remoteAddress);
      closeChannel(channel);
      super.close(ctx, promise);

      if (channelEventListener != null) {
        putRemotingEvent(new RemotingEvent(RemotingEventType.CLOSE, remoteAddress, channel));
      }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

      Channel channel = new NettyChannel(ctx);

      final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(channel);
      LOGGER.warn("CLIENT : exceptionCaught {}", remoteAddress);
      LOGGER.warn("CLIENT : exceptionCaught exception.", cause);
      closeChannel(channel);
      if (channelEventListener != null) {
        putRemotingEvent(new RemotingEvent(RemotingEventType.EXCEPTION, remoteAddress, channel));
      }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
      if (evt instanceof IdleStateEvent) {
        IdleStateEvent event = (IdleStateEvent) evt;

        Channel channel = new NettyChannel(ctx);

        final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(channel);

        if (event.state().equals(io.netty.handler.timeout.IdleState.ALL_IDLE)) {
          LOGGER.warn("CLIENT : IDLE [{}]", remoteAddress);
          closeChannel(channel);
        }

        if (channelEventListener != null) {
          RemotingEventType remotingEventType = RemotingEventType.valueOf(event.state().name());
          putRemotingEvent(new RemotingEvent(remotingEventType, remoteAddress, channel));
        }
      }

      ctx.fireUserEventTriggered(evt);
    }
  }
}
/** @author Robert HG ([email protected]) on 8/15/14. 抽象节点 */
public abstract class AbstractJobNode<T extends Node, App extends Application> implements JobNode {

  protected static final Logger LOGGER = LoggerFactory.getLogger(JobNode.class);

  protected Registry registry;
  protected T node;
  protected Config config;
  protected App application;
  private List<NodeChangeListener> nodeChangeListeners;
  private List<MasterChangeListener> masterChangeListeners;
  private EventCenterFactory eventCenterFactory =
      ExtensionLoader.getExtensionLoader(EventCenterFactory.class).getAdaptiveExtension();
  private AtomicBoolean started = new AtomicBoolean(false);

  public AbstractJobNode() {
    application = getApplication();
    config = JobNodeConfigFactory.getDefaultConfig();
    application.setConfig(config);
    nodeChangeListeners = new ArrayList<NodeChangeListener>();
    masterChangeListeners = new ArrayList<MasterChangeListener>();
  }

  public final void start() {
    try {
      if (started.compareAndSet(false, true)) {
        // 初始化配置
        initConfig();

        preRemotingStart();

        remotingStart();

        afterRemotingStart();

        initRegistry();

        registry.register(node);

        LOGGER.info("Start success!");
      }
    } catch (Throwable e) {
      LOGGER.error("Start failed!", e);
    }
  }

  public final void stop() {
    try {
      if (started.compareAndSet(true, false)) {

        registry.unregister(node);

        preRemotingStop();

        remotingStop();

        afterRemotingStop();

        LOGGER.info("Stop success!");
      }
    } catch (Throwable e) {
      LOGGER.error("Stop failed!", e);
    }
  }

  @Override
  public void destroy() {
    try {
      registry.destroy();
      LOGGER.info("Destroy success!");
    } catch (Throwable e) {
      LOGGER.error("Destroy failed!", e);
    }
  }

  protected void initConfig() {
    application.setEventCenter(eventCenterFactory.getEventCenter(config));

    application.setCommandBodyWrapper(new CommandBodyWrapper(config));
    application.setMasterElector(new MasterElector(application));
    application.getMasterElector().addMasterChangeListener(masterChangeListeners);
    application.setRegistryStatMonitor(new RegistryStatMonitor(application));

    node = NodeFactory.create(getNodeClass(), config);
    config.setNodeType(node.getNodeType());

    LOGGER.info("Current node config :{}", config);

    // 订阅的node管理
    SubscribedNodeManager subscribedNodeManager = new SubscribedNodeManager(application);
    application.setSubscribedNodeManager(subscribedNodeManager);
    nodeChangeListeners.add(subscribedNodeManager);
    // 用于master选举的监听器
    nodeChangeListeners.add(new MasterElectionListener(application));
    // 监听自己节点变化(如,当前节点被禁用了)
    nodeChangeListeners.add(new SelfChangeListener(application));
  }

  private void initRegistry() {
    registry = RegistryFactory.getRegistry(application);
    if (registry instanceof AbstractRegistry) {
      ((AbstractRegistry) registry).setNode(node);
    }
    registry.subscribe(
        node,
        new NotifyListener() {
          private final Logger NOTIFY_LOGGER = LoggerFactory.getLogger(NotifyListener.class);

          @Override
          public void notify(NotifyEvent event, List<Node> nodes) {
            if (CollectionUtils.isEmpty(nodes)) {
              return;
            }
            switch (event) {
              case ADD:
                for (NodeChangeListener listener : nodeChangeListeners) {
                  try {
                    listener.addNodes(nodes);
                  } catch (Throwable t) {
                    NOTIFY_LOGGER.error(
                        "{} add nodes failed , cause: {}",
                        listener.getClass().getName(),
                        t.getMessage(),
                        t);
                  }
                }
                break;
              case REMOVE:
                for (NodeChangeListener listener : nodeChangeListeners) {
                  try {
                    listener.removeNodes(nodes);
                  } catch (Throwable t) {
                    NOTIFY_LOGGER.error(
                        "{} remove nodes failed , cause: {}",
                        listener.getClass().getName(),
                        t.getMessage(),
                        t);
                  }
                }
                break;
            }
          }
        });
  }

  protected abstract void remotingStart();

  protected abstract void remotingStop();

  protected void preRemotingStart() {
    // 检查identity是否重复

  }

  protected void afterRemotingStart() {}

  protected void preRemotingStop() {}

  protected void afterRemotingStop() {}

  @SuppressWarnings("unchecked")
  private App getApplication() {
    try {
      return ((Class<App>) GenericsUtils.getSuperClassGenericType(this.getClass(), 1))
          .newInstance();
    } catch (InstantiationException e) {
      throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }

  @SuppressWarnings("unchecked")
  private Class<T> getNodeClass() {
    return (Class<T>) GenericsUtils.getSuperClassGenericType(this.getClass(), 0);
  }

  /** 设置zookeeper注册中心地址 */
  public void setRegistryAddress(String registryAddress) {
    config.setRegistryAddress(registryAddress);
  }

  /** 设置远程调用超时时间 */
  public void setInvokeTimeoutMillis(int invokeTimeoutMillis) {
    config.setInvokeTimeoutMillis(invokeTimeoutMillis);
  }

  /** 设置集群名字 */
  public void setClusterName(String clusterName) {
    config.setClusterName(clusterName);
  }

  /** 节点标识(必须要保证这个标识是唯一的才能设置,请谨慎设置) 这个是非必须设置的,建议使用系统默认生成 */
  public void setIdentity(String identity) {
    config.setIdentity(identity);
  }

  /** 添加节点监听器 */
  public void addNodeChangeListener(NodeChangeListener notifyListener) {
    if (notifyListener != null) {
      nodeChangeListeners.add(notifyListener);
    }
  }

  /** 添加 master 节点变化监听器 */
  public void addMasterChangeListener(MasterChangeListener masterChangeListener) {
    if (masterChangeListener != null) {
      masterChangeListeners.add(masterChangeListener);
    }
  }

  /** 设置额外的配置参数 */
  public void addConfig(String key, String value) {
    config.setParameter(key, value);
  }
}
/** Robert HG ([email protected]) on 6/5/15. */
@Component
public class RegistryService implements InitializingBean {

  private static final Logger LOGGER = LoggerFactory.getLogger(RegistryService.class);
  @Autowired NodeMemoryDatabase nodeMemoryDatabase;
  @Autowired AdminAppContext appContext;
  @Autowired NodeOnOfflineLogRepo nodeOnOfflineLogRepo;

  private Registry registry;

  private void register() {

    registry.subscribe(
        appContext.getNode(),
        new NotifyListener() {
          @Override
          public void notify(NotifyEvent event, List<Node> nodes) {
            if (CollectionUtils.isEmpty(nodes)) {
              return;
            }
            switch (event) {
              case ADD:
                nodeMemoryDatabase.addNode(nodes);
                LOGGER.info("ADD NODE " + nodes);
                break;
              case REMOVE:
                nodeMemoryDatabase.removeNode(nodes);
                LOGGER.info("REMOVE NODE " + nodes);
                break;
            }
            // 记录日志
            addLog(event, nodes);
          }
        });
  }

  public List<Node> getOnlineNodes(NodeRequest request) {
    return nodeMemoryDatabase.search(request);
  }

  /** 记录节点上下线日志 */
  private void addLog(NotifyEvent event, List<Node> nodes) {
    List<NodeOnOfflineLog> logs = new ArrayList<NodeOnOfflineLog>(nodes.size());

    for (Node node : nodes) {
      NodeOnOfflineLog log = new NodeOnOfflineLog();
      log.setLogTime(new Date());
      log.setEvent(event == NotifyEvent.ADD ? "ONLINE" : "OFFLINE");

      log.setClusterName(node.getClusterName());
      log.setCreateTime(node.getCreateTime());
      log.setGroup(node.getGroup());
      log.setHostName(node.getHostName());
      log.setIdentity(node.getIdentity());
      log.setIp(node.getIp());
      log.setPort(node.getPort());
      log.setThreads(node.getThreads());
      log.setNodeType(node.getNodeType());

      logs.add(log);
    }

    nodeOnOfflineLogRepo.insert(logs);
  }

  @Override
  public void afterPropertiesSet() throws Exception {

    registry = RegistryFactory.getRegistry(appContext);

    register();
  }
}
/**
 * 内部根据用户参数决定是否采用延迟批量刷盘的策略,来提高吞吐量 批量刷盘有两种情况: 1. 内存的日志量超过了设置的阀值 2. 每3S检查一次内存中是否有日志,如果有就那么刷盘
 *
 * @author Robert HG ([email protected]) on 10/2/15.
 */
public class JobLoggerDelegate implements JobLogger {

  private static final Logger LOGGER = LoggerFactory.getLogger(JobLoggerDelegate.class);

  // 3S 检查输盘一次日志
  private int flushPeriod;

  private JobLogger jobLogger;
  private boolean lazyLog = false;
  private ScheduledExecutorService executor;
  private ScheduledFuture scheduledFuture;
  private BlockingQueue<JobLogPo> memoryQueue;
  // 日志批量刷盘数量
  private int batchFlushSize = 100;
  private int overflowSize = 10000;
  // 内存中最大的日志量阀值
  private int maxMemoryLogSize;
  private AtomicBoolean flushing = new AtomicBoolean(false);

  public JobLoggerDelegate(Config config) {
    JobLoggerFactory jobLoggerFactory =
        ExtensionLoader.getExtensionLoader(JobLoggerFactory.class).getAdaptiveExtension();
    jobLogger = jobLoggerFactory.getJobLogger(config);
    lazyLog = config.getParameter(Constants.LAZY_JOB_LOGGER, false);
    if (lazyLog) {

      // 无界Queue
      memoryQueue = new LinkedBlockingQueue<JobLogPo>();
      maxMemoryLogSize = config.getParameter(Constants.LAZY_JOB_LOGGER_MEM_SIZE, 1000);
      flushPeriod = config.getParameter(Constants.LAZY_JOB_LOGGER_CHECK_PERIOD, 3);

      executor =
          Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("LazyJobLogger"));
      scheduledFuture =
          executor.scheduleWithFixedDelay(
              new Runnable() {
                @Override
                public void run() {
                  try {
                    if (flushing.compareAndSet(false, true)) {
                      checkAndFlush();
                    }
                  } catch (Throwable t) {
                    LOGGER.error("CheckAndFlush log error", t);
                  }
                }
              },
              flushPeriod,
              flushPeriod,
              TimeUnit.SECONDS);
    }
  }

  /** 检查内存中是否有日志,如果有就批量刷盘 */
  private void checkAndFlush() {
    try {
      int nowSize = memoryQueue.size();
      if (nowSize == 0) {
        return;
      }
      List<JobLogPo> batch = new ArrayList<JobLogPo>();
      for (int i = 0; i < nowSize; i++) {
        JobLogPo jobLogPo = memoryQueue.poll();
        batch.add(jobLogPo);

        if (batch.size() >= batchFlushSize) {
          flush(batch);
        }
      }
      if (batch.size() > 0) {
        flush(batch);
      }

    } finally {
      flushing.compareAndSet(true, false);
    }
  }

  private void checkOverflowSize() {
    if (memoryQueue.size() > overflowSize) {
      throw new JobLogException(
          "Memory Log size is "
              + memoryQueue.size()
              + " , please check the JobLogger is available");
    }
  }

  private void flush(List<JobLogPo> batch) {
    boolean flushSuccess = false;
    try {
      jobLogger.log(batch);
      flushSuccess = true;
    } finally {
      if (!flushSuccess) {
        memoryQueue.addAll(batch);
      }
      batch.clear();
    }
  }

  /** 检查内存中的日志量是否超过阀值,如果超过需要批量刷盘日志 */
  private void checkCapacity() {
    if (memoryQueue.size() > maxMemoryLogSize) {
      // 超过阀值,需要批量刷盘
      if (flushing.compareAndSet(false, true)) {
        // 这里可以采用new Thread, 因为这里只会同时new一个
        new Thread(
                new Runnable() {
                  @Override
                  public void run() {
                    try {
                      checkAndFlush();
                    } catch (Throwable t) {
                      LOGGER.error("Capacity full flush error", t);
                    }
                  }
                })
            .start();
      }
    }
  }

  @Override
  public void log(JobLogPo jobLogPo) {
    if (jobLogPo == null) {
      return;
    }
    if (lazyLog) {
      checkOverflowSize();
      memoryQueue.offer(jobLogPo);
      checkCapacity();
    } else {
      jobLogger.log(jobLogPo);
    }
  }

  @Override
  public void log(List<JobLogPo> jobLogPos) {
    if (CollectionUtils.isEmpty(jobLogPos)) {
      return;
    }
    if (lazyLog) {
      checkOverflowSize();
      for (JobLogPo jobLogPo : jobLogPos) {
        memoryQueue.offer(jobLogPo);
      }
      // checkCapacity
      checkCapacity();
    } else {
      jobLogger.log(jobLogPos);
    }
  }

  @Override
  public PageResponse<JobLogPo> search(JobLoggerRequest request) {
    return jobLogger.search(request);
  }
}
/** @author Robert HG ([email protected]) on 8/14/14. 接受任务并执行 */
public class JobPushProcessor extends AbstractProcessor {

  private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.TaskTracker);

  private RetryScheduler retryScheduler;
  private JobRunnerCallback jobRunnerCallback;
  private RemotingClientDelegate remotingClient;

  protected JobPushProcessor(TaskTrackerApplication application) {
    super(application);
    this.remotingClient = application.getRemotingClient();
    retryScheduler =
        new RetryScheduler<TaskTrackerJobResult>(application, 3) {
          @Override
          protected boolean isRemotingEnable() {
            return remotingClient.isServerEnable();
          }

          @Override
          protected boolean retry(List<TaskTrackerJobResult> results) {
            return retrySendJobResults(results);
          }
        };
    retryScheduler.setName("JobPush");
    retryScheduler.start();

    // 线程安全的
    jobRunnerCallback = new JobRunnerCallback();
  }

  @Override
  public RemotingCommand processRequest(ChannelHandlerContext ctx, final RemotingCommand request)
      throws RemotingCommandException {

    JobPushRequest requestBody = request.getBody();

    // JobTracker 分发来的 job
    final JobWrapper jobWrapper = requestBody.getJobWrapper();

    try {
      application.getRunnerPool().execute(jobWrapper, jobRunnerCallback);
    } catch (NoAvailableJobRunnerException e) {
      // 任务推送失败
      return RemotingCommand.createResponseCommand(
          JobProtos.ResponseCode.NO_AVAILABLE_JOB_RUNNER.code(),
          "job push failure , no available job runner!");
    }

    // 任务推送成功
    return RemotingCommand.createResponseCommand(
        JobProtos.ResponseCode.JOB_PUSH_SUCCESS.code(), "job push success!");
  }

  /** 任务执行的回调(任务执行完之后线程回调这个函数) */
  private class JobRunnerCallback implements RunnerCallback {
    @Override
    public JobWrapper runComplete(Response response) {
      // 发送消息给 JobTracker
      final TaskTrackerJobResult taskTrackerJobResult = new TaskTrackerJobResult();
      taskTrackerJobResult.setTime(SystemClock.now());
      taskTrackerJobResult.setJobWrapper(response.getJobWrapper());
      taskTrackerJobResult.setAction(response.getAction());
      taskTrackerJobResult.setMsg(response.getMsg());
      TtJobFinishedRequest requestBody =
          application.getCommandBodyWrapper().wrapper(new TtJobFinishedRequest());
      requestBody.addJobResult(taskTrackerJobResult);
      requestBody.setReceiveNewJob(response.isReceiveNewJob()); // 设置可以接受新任务

      int requestCode = JobProtos.RequestCode.JOB_FINISHED.code();

      RemotingCommand request = RemotingCommand.createRequestCommand(requestCode, requestBody);

      final Response returnResponse = new Response();

      try {
        final CountDownLatch latch = new CountDownLatch(1);
        remotingClient.invokeAsync(
            request,
            new InvokeCallback() {
              @Override
              public void operationComplete(ResponseFuture responseFuture) {
                try {
                  RemotingCommand commandResponse = responseFuture.getResponseCommand();

                  if (commandResponse != null
                      && commandResponse.getCode() == RemotingProtos.ResponseCode.SUCCESS.code()) {
                    JobPushRequest jobPushRequest = commandResponse.getBody();
                    if (jobPushRequest != null) {
                      LOGGER.info("Get new job :{}", jobPushRequest.getJobWrapper());
                      returnResponse.setJobWrapper(jobPushRequest.getJobWrapper());
                    }
                  } else {
                    LOGGER.info("Job feedback failed, save local files。{}", taskTrackerJobResult);
                    try {
                      retryScheduler.inSchedule(
                          taskTrackerJobResult.getJobWrapper().getJobId().concat("_")
                              + SystemClock.now(),
                          taskTrackerJobResult);
                    } catch (Exception e) {
                      LOGGER.error("Job feedback failed", e);
                    }
                  }
                } finally {
                  latch.countDown();
                }
              }
            });

        try {
          latch.await(Constants.LATCH_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
          throw new RequestTimeoutException(e);
        }
      } catch (JobTrackerNotFoundException e) {
        try {
          LOGGER.warn("No job tracker available! save local files.");
          retryScheduler.inSchedule(
              taskTrackerJobResult.getJobWrapper().getJobId().concat("_") + SystemClock.now(),
              taskTrackerJobResult);
        } catch (Exception e1) {
          LOGGER.error("Save files failed, {}", taskTrackerJobResult.getJobWrapper(), e1);
        }
      }

      return returnResponse.getJobWrapper();
    }
  }

  /**
   * 发送JobResults
   *
   * @param results
   * @return
   */
  private boolean retrySendJobResults(List<TaskTrackerJobResult> results) {
    // 发送消息给 JobTracker
    TtJobFinishedRequest requestBody =
        application.getCommandBodyWrapper().wrapper(new TtJobFinishedRequest());
    requestBody.setTaskTrackerJobResults(results);
    requestBody.setReSend(true);

    int requestCode = JobProtos.RequestCode.JOB_FINISHED.code();
    RemotingCommand request = RemotingCommand.createRequestCommand(requestCode, requestBody);

    try {
      // 这里一定要用同步,不然异步会发生文件锁,死锁
      RemotingCommand commandResponse = remotingClient.invokeSync(request);
      if (commandResponse != null
          && commandResponse.getCode() == RemotingProtos.ResponseCode.SUCCESS.code()) {
        return true;
      } else {
        LOGGER.warn("Send job failed, {}", commandResponse);
        return false;
      }
    } catch (JobTrackerNotFoundException e) {
      LOGGER.error("Retry send job result failed! jobResults={}", results, e);
    }
    return false;
  }
}
/**
 * 主要用于 curl
 *
 * @author Robert HG ([email protected]) on 10/26/15.
 */
public class CommandCenter {

  private final Logger LOGGER = LoggerFactory.getLogger(CommandCenter.class);
  private ExecutorService commandExecutor;
  private AtomicBoolean start = new AtomicBoolean(false);
  private final Map<String, CommandProcessor> processorMap =
      new HashMap<String, CommandProcessor>();

  private Config config;
  private int port;

  public CommandCenter(Config config) {
    this.config = config;
  }

  public void start() throws CommandException {
    try {
      if (start.compareAndSet(false, true)) {

        port = config.getParameter("lts.command.port", 8719);

        commandExecutor =
            new ThreadPoolExecutor(
                Constants.AVAILABLE_PROCESSOR,
                Constants.AVAILABLE_PROCESSOR,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(100),
                new ThreadPoolExecutor.DiscardPolicy());

        ServerSocket serverSocket = getServerSocket();
        // 开启监听命令
        startServerListener(serverSocket);

        LOGGER.info("Start CommandCenter succeed at port {}", port);
      }
    } catch (Exception t) {
      LOGGER.error(
          "Start CommandCenter error at port {} , use lts.command.port config change the port.",
          port,
          t);
      throw new CommandException(t);
    }
  }

  private ServerSocket getServerSocket() throws IOException {
    ServerSocket serverSocket = null;
    try {
      serverSocket = new ServerSocket(port);
    } catch (BindException e) {
      if (e.getMessage().contains("Address already in use")) {
        port = port + 1;
        serverSocket = getServerSocket();
      } else {
        throw e;
      }
    }
    return serverSocket;
  }

  private void startServerListener(final ServerSocket serverSocket) {

    new Thread(
            new Runnable() {
              @Override
              public void run() {

                while (start.get()) {
                  Socket socket = null;

                  try {
                    socket = serverSocket.accept();
                    if (socket == null) {
                      continue;
                    }
                    commandExecutor.submit(new EventRunnable(socket));

                  } catch (Throwable t) {
                    LOGGER.error("Accept error ", t);

                    try {
                      Thread.sleep(1000); // 1s
                    } catch (InterruptedException ignored) {
                    }
                  }
                }
              }
            })
        .start();
  }

  public void stop() {
    try {
      if (start.compareAndSet(true, false)) {
        commandExecutor.shutdownNow();
        LOGGER.info("Stop CommandCenter succeed ");
      }
    } catch (Throwable t) {
      LOGGER.error("Stop CommandCenter error ", t);
    }
  }

  public int getPort() {
    return port;
  }

  public void registerCommand(String command, CommandProcessor processor) {

    if (StringUtils.isEmpty(command)) {
      return;
    }
    processorMap.put(command, processor);
  }

  private CommandProcessor getCommandProcessor(String command) {
    return processorMap.get(command);
  }

  class EventRunnable implements Runnable {

    private Socket socket;

    public EventRunnable(Socket socket) {
      this.socket = socket;
    }

    @Override
    public void run() {

      BufferedReader in = null;
      PrintWriter out = null;

      try {
        in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
        OutputStream outputStream = socket.getOutputStream();
        out = new PrintWriter(outputStream);

        String line = in.readLine();
        CommandRequest request = CommandRequest.parse(line);

        out.print("HTTP/1.1 200 OK\r\n\r\n");
        out.flush();
        if (StringUtils.isEmpty(request.getCommand())) {
          out.println("Command is blank");
          out.flush();
          return;
        }

        CommandProcessor commandProcessor = getCommandProcessor(request.getCommand());
        if (commandProcessor != null) {
          commandProcessor.execute(outputStream, request);
        } else {
          out.println("Can not find the command:[" + request.getCommand() + "]");
        }
        out.flush();

      } catch (Throwable t) {
        LOGGER.error("EventRunnable error", t);

        try {
          if (out != null) {
            out.println("CommandCenter error, message is " + t.getMessage());
            out.flush();
          }
        } catch (Exception e) {
          LOGGER.error("EventRunnable error", t);
        }

      } finally {
        try {
          if (out != null) {
            out.close();
          }
          if (in != null) {
            in.close();
          }
          socket.close();
        } catch (Exception e) {
          LOGGER.error("EventRunnable close resource error", e);
        }
      }
    }
  }
}
예제 #10
0
/**
 * 参考dubbo
 *
 * @author Robert HG ([email protected]) on 5/19/15.
 */
public final class Version {

  private Version() {}

  private static final Logger LOGGER = LoggerFactory.getLogger(Version.class);

  private static final String VERSION = getVersion(Version.class, "1.6.4-SNAPSHOT");

  static {
    // 检查是否存在重复的jar包
    Version.checkDuplicate(Version.class);
  }

  public static String getVersion() {
    return VERSION;
  }

  public static String getVersion(Class<?> cls, String defaultVersion) {
    try {
      // 首先查找MANIFEST.MF规范中的版本号
      String version = cls.getPackage().getImplementationVersion();
      if (version == null || version.length() == 0) {
        version = cls.getPackage().getSpecificationVersion();
      }
      if (version == null || version.length() == 0) {
        // 如果规范中没有版本号,基于jar包名获取版本号
        CodeSource codeSource = cls.getProtectionDomain().getCodeSource();
        if (codeSource == null) {
          LOGGER.info(
              "No codeSource for class "
                  + cls.getName()
                  + " when getVersion, use default version "
                  + defaultVersion);
        } else {
          String file = codeSource.getLocation().getFile();
          if (file != null && file.length() > 0 && file.endsWith(".jar")) {
            file = file.substring(0, file.length() - 4);
            int i = file.lastIndexOf('/');
            if (i >= 0) {
              file = file.substring(i + 1);
            }
            i = file.indexOf("-");
            if (i >= 0) {
              file = file.substring(i + 1);
            }
            while (file.length() > 0 && !Character.isDigit(file.charAt(0))) {
              i = file.indexOf("-");
              if (i >= 0) {
                file = file.substring(i + 1);
              } else {
                break;
              }
            }
            version = file;
          }
        }
      }
      // 返回版本号,如果为空返回缺省版本号
      return version == null || version.length() == 0 ? defaultVersion : version;
    } catch (Throwable e) { // 防御性容错
      // 忽略异常,返回缺省版本号
      LOGGER.error("return default version, ignore exception " + e.getMessage(), e);
      return defaultVersion;
    }
  }

  public static void checkDuplicate(Class<?> cls, boolean failOnError) {
    checkDuplicate(cls.getName().replace('.', '/') + ".class", failOnError);
  }

  public static void checkDuplicate(Class<?> cls) {
    checkDuplicate(cls, false);
  }

  public static void checkDuplicate(String path, boolean failOnError) {
    try {
      // 在ClassPath搜文件
      Enumeration<URL> urls = ClassHelper.getCallerClassLoader(Version.class).getResources(path);
      Set<String> files = new HashSet<String>();
      while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        if (url != null) {
          String file = url.getFile();
          if (file != null && file.length() > 0) {
            files.add(file);
          }
        }
      }
      // 如果有多个,就表示重复
      if (files.size() > 1) {
        String error = "Duplicate class " + path + " in " + files.size() + " jar " + files;
        if (failOnError) {
          throw new IllegalStateException(error);
        } else {
          LOGGER.error(error);
        }
      }
    } catch (Throwable e) { // 防御性容错
      LOGGER.error(e.getMessage(), e);
    }
  }
}