/** * Copyright 2016 benjobs * <p> * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.opencron.server.job; import org.opencron.common.utils.CommonUtils; import org.opencron.common.utils.HttpUtils; import org.opencron.server.domain.Agent; import org.opencron.server.service.AgentService; import org.opencron.server.service.ConfigService; import org.opencron.server.service.ExecuteService; import org.opencron.server.service.NoticeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.Serializable; import java.net.ServerSocket; import java.net.Socket; import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** * Created by benjobs on 2016/12/15. */ @Component public class OpencronMonitor implements Serializable { private final Logger logger = LoggerFactory.getLogger(OpencronMonitor.class); public static int port; private volatile boolean running = false; private ConcurrentHashMap<Class, ObjectAction> actionMapping = new ConcurrentHashMap<Class, ObjectAction>(); private Map<Agent, Long> successConnStatus = new ConcurrentHashMap<Agent, Long>(0); private Map<String, Agent> agentMap = new ConcurrentHashMap<String, Agent>(0); private Thread connWatchDog; private long keepAliveDelay = 1000 * 10;//10秒一次心跳 @Autowired private AgentService agentService; @Autowired private ConfigService configService; @Autowired private NoticeService noticeService; @Autowired private ExecuteService executeService; /** * 要处理客户端发来的对象,并返回一个对象,可实现该接口。 */ public interface ObjectAction { void doAction(Object rev); } public final class DefaultObjectAction implements ObjectAction { public void doAction(Object rev) { String ip = rev.toString(); if (agentMap.get(ip) == null) { Agent agent = agentService.getByHost(rev.toString()); agentMap.put(ip, agent); } successConnStatus.put(agentMap.get(ip), System.currentTimeMillis()); } } public void start() { logger.info("[opencron]:checking Agent connection..."); this.port = HttpUtils.freePort(); if (running) return; running = true; connWatchDog = new Thread(new ConnWatchDog()); connWatchDog.start(); new Timer().schedule(new TimerTask() { @Override public void run() { List<Agent> agents = agentService.getAll(); if (agents.size() != successConnStatus.size()) { for (Agent agent: agents) { if (successConnStatus.get(agent) == null) { boolean ping = executeService.ping(agent); if (ping) { agent.setStatus(true); agentService.merge(agent); }else { if (agent.getStatus()) { agent.setStatus(false); agentService.merge(agent); } if (CommonUtils.isEmpty(agent.getNotifyTime()) || new Date().getTime() - agent.getNotifyTime().getTime() >= configService.getSysConfig().getSpaceTime() * 60 * 1000) { noticeService.notice(agent); //记录本次任务失败的时间 agent.setNotifyTime(new Date()); agentService.merge(agent); } } } } } for (Map.Entry<Agent, Long> entry : successConnStatus.entrySet()) { long lastAliveTime = entry.getValue(); Agent agent = entry.getKey(); //已经失联的状态,再次通知连接 if (!agent.getStatus()) { boolean ping = executeService.ping(agent); if (ping) { agent.setStatus(true); agentService.merge(agent); continue; } } if (System.currentTimeMillis() - lastAliveTime > OpencronMonitor.this.keepAliveDelay) { if (CommonUtils.isEmpty(agent.getNotifyTime()) || new Date().getTime() - agent.getNotifyTime().getTime() >= configService.getSysConfig().getSpaceTime() * 60 * 1000) { agent.setStatus(false); noticeService.notice(agent); //记录本次任务失败的时间 agent.setNotifyTime(new Date()); agentService.merge(agent); } if (agent.getStatus()) { agent.setStatus(false); agentService.merge(agent); } } else { if (!agent.getStatus()) { agent.setStatus(true); agentService.merge(agent); } } } } }, 0, keepAliveDelay); } @SuppressWarnings("deprecation") public void stop() { if (running) running = false; if (connWatchDog != null) connWatchDog.stop(); } class ConnWatchDog implements Runnable { public void run() { try { ServerSocket serverSocket = new ServerSocket(port, 5); while (running) { Socket socket = serverSocket.accept(); new Thread(new SocketAction(socket)).start(); } } catch (IOException e) { e.printStackTrace(); OpencronMonitor.this.stop(); } } } class SocketAction implements Runnable { private Socket socket; private boolean run = true; public SocketAction(Socket socket) { this.socket = socket; } public void run() { while (running && run) { try { InputStream in = socket.getInputStream(); if (in.available() > 0) { ObjectInputStream inputStream = new ObjectInputStream(in); Object obj = inputStream.readObject(); ObjectAction action = actionMapping.get(obj.getClass()); action = action == null ? new DefaultObjectAction() : action; action.doAction(obj); } else { Thread.sleep(10); } } catch (Exception e) { e.printStackTrace(); } } } } }