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

uw.task.conf.TaskServerConfig Maven / Gradle / Ivy

package uw.task.conf;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Binding.DestinationType;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.postprocessor.GUnzipPostProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import uw.task.TaskCroner;
import uw.task.TaskData;
import uw.task.TaskRunner;
import uw.task.api.TaskAPI;
import uw.task.entity.TaskCronerConfig;
import uw.task.entity.TaskRunnerConfig;
import uw.task.mq.TaskConsumer;

/**
 * 根据从服务器端加载的信息来配置服务和任务项。
 * 
 * @author axeon
 */
@Component
public class TaskServerConfig {

	private static final Logger log = LoggerFactory.getLogger(TaskServerConfig.class);

	@Autowired
	ApplicationContext context;

	@Autowired
	ConnectionFactory connectionFactory;

	@Autowired
	TaskConsumer taskConsumer;

	@Autowired
	TaskProperties taskProperties;

	@Autowired
	TaskAPI taskAPI;

	@Autowired
	RabbitAdmin rabbitAdmin;

	@Autowired
	ObjectMapper objectMapper;

	/**
	 * 是否已经跑过一次
	 */
	boolean isRan = false;

	/**
	 * container缓存。key=主机配置,key=任务名,value=container。
	 */
	private ConcurrentHashMap> runnerContainerMap = new ConcurrentHashMap<>();

	/**
	 * Runner任务配置缓存。
	 */
	private ConcurrentHashMap runnerConfigMap = new ConcurrentHashMap<>();

	/**
	 * Cron任务配置缓存。
	 */
	private ConcurrentHashMap cronerConfigMap = new ConcurrentHashMap<>();

	/**
	 * Runner任务实例缓存。
	 */
	private ConcurrentHashMap> runnerMap = new ConcurrentHashMap<>();

	/**
	 * Cron任务实例缓存。
	 */
	private ConcurrentHashMap cronerMap = new ConcurrentHashMap<>();

	/**
	 * 泛型类型缓存
	 */
	private ConcurrentHashMap dataParamMap = new ConcurrentHashMap<>();

	/**
	 * 运行主机配置
	 */
	private List hostConfig = null;

	/**
	 * 上次更新配置时间
	 */
	private long lastUpdateTime = 0;

	
	/**
	 * 获得任务配置
	 * 
	 * @param taskClass
	 * @return
	 */
	public TaskRunnerConfig getRunnerConfig(String taskClass) {
		TaskRunnerConfig config = runnerConfigMap.get(taskClass);
		if (config == null) {
			if (log.isWarnEnabled()) {
				log.warn("获得Runner:{}服务端配置失败,启用默认配置项!", taskClass);
			}
			config = new TaskRunnerConfig();
			config.setId(0);
			config.setTaskClass(taskClass);
			config.setConsumerNum(5);
			config.setRateLimitType(0);
			config.setRateLimitValue(999);
			config.setRateLimitTime(1);
			config.setRateLimitWait(60);
			config.setRetryTimesByOverrated(3);
			config.setRetryTimesByPartner(3);
			config.setStatus(1);
			runnerConfigMap.put(taskClass, config);
		}
		return config;
	}

	/**
	 * 获得任务
	 * 
	 * @param taskClass
	 * @return
	 */
	public TaskRunner getRunner(String taskClass) {
		return runnerMap.get(taskClass);
	}

	/**
	 * 转换taskdata。
	 * 
	 * @param taskData
	 * @return
	 */
	public TaskData convertTaskData(TaskData taskData) {
		TaskData convertData = null;
		JavaType type = dataParamMap.get(taskData.getTaskClass());
		if (type != null) {
			try {
				convertData = objectMapper.convertValue(taskData, type);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
		}
		return convertData == null ? taskData : convertData;
	}

	/**
	 * 配置RabbitAdmin
	 * 
	 * @param connectionFactory
	 * @return
	 */
	@Bean
	RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
		return new RabbitAdmin(connectionFactory);
	}

	/**
	 * 更新主机状态。30秒更新一次。
	 */
	@Scheduled(fixedRate = 30000)
	public void updateStatus() {
		taskAPI.updateHostStatus();
	}

	/**
	 * 注册当前所有的服务。 每隔5分钟刷新一次。
	 */
	@Scheduled(fixedRate = 300000)
	public void updateConfig() {
		long startUpdateTimeMilles = System.currentTimeMillis();

		// 刷新主机状态。
		List newHostConfig = taskAPI.getHostConfig();

		// 检查有没有需要删除的
		if (hostConfig != null) {
			for (String host : hostConfig) {
				if (!newHostConfig.contains(host)) {
					// 这个需要删除掉队列监听了。
					ConcurrentHashMap map = runnerContainerMap.get(host);
					if (map != null) {
						for (SimpleMessageListenerContainer container : map.values()) {
							container.stop();
						}
					}
				}
			}
		}
		// 检查是否有新增
		for (String host : newHostConfig) {
			if (hostConfig == null || !hostConfig.contains(host)) {
				for (String taskClass : runnerMap.keySet()) {
					registerTask(host, taskClass);
				}
			}
		}
		// 设置状态
		hostConfig = newHostConfig;

		// 取得有变化的croner配置列表
		List cronerConfigList = updateCronerConfig();
		// 取得有变化的runner配置列表
		List runnerConfigList = updateRunnerConfig();

		if (isRan) {
			// 此时执行更新操作
			// 改Cron配置
			if (cronerConfigList != null) {
				for (TaskCronerConfig tcc : cronerConfigList) {
					TaskCroner tc = cronerMap.get(tcc.getTaskClass());
					if (tc != null) {
						try {
							tc.setCronExpression(tcc.getCron());
							tc.setRunType(tc.getRunType());
							tc.setRunTarget(tc.getRunTarget());
						} catch (Exception e) {
							log.error(e.getMessage(), e);
						}
					} else {
						log.warn("更新TaskCroner配置时,未找到匹配的任务:{}", tcc.getTaskClass());
					}
				}
			}
			// 改Runner配置,逐一循环并配置。
			if (runnerConfigList != null) {
				for (TaskRunnerConfig trc : runnerConfigList) {
					Collection> list = runnerContainerMap
							.values();
					for (ConcurrentHashMap map : list) {
						SimpleMessageListenerContainer container = map.get(trc.getTaskClass());
						if (container != null) {
							try {
								container.setConcurrentConsumers(trc.getConsumerNum());
								container.setPrefetchCount(trc.getConsumerNum());
							} catch (Exception e) {
								log.error(e.getMessage(), e);
							}
						} else {
							log.warn("更新TaskRunner配置时,未找到匹配的任务:{}", trc.getTaskClass());
						}
					}
				}
			}

		} else {
			// 第一次执行初始化操作
			isRan = true;
			// 设置当前主机上所有的TaskCroner
			Map cronerMap = context.getBeansOfType(TaskCroner.class);
			for (Entry kv : cronerMap.entrySet()) {
				try {
					// 拿到任务类名
					String taskClass = kv.getValue().getClass().getName();
					TaskCronerConfig config = cronerConfigMap.get(taskClass);
					TaskCroner tc = kv.getValue();
					// 配置croner任务
					if (config == null) {
						tc.setCronExpression(tc.initCronExpression());
						tc.setRunType(tc.initRunType());
						tc.setRunTarget(tc.initRunTarget());
					} else {
						tc.setCronExpression(config.getCron());
						tc.setRunType(config.getRunType());
						tc.setRunTarget(config.getTargetHost());
					}
					// 启动croner任务
					tc.start();
				} catch (Exception e) {
					log.error(e.getMessage(), e);
				}
			}

			// 获得当前主机上所有的TaskRunner
			Map runnerInstanceMap = context.getBeansOfType(TaskRunner.class);
			for (Entry kv : runnerInstanceMap.entrySet()) {
				try {
					// 拿到任务类名
					String taskClass = kv.getValue().getClass().getName();
					runnerMap.put(taskClass, kv.getValue());
					// 放在最后,防止出幺蛾子
					constructTaskDataType(taskClass, kv.getValue());
				} catch (Exception e) {
					log.error(e.getMessage(), e);
				}
			}

			// 循环创建监听队列
			for (String host : hostConfig) {
				for (String taskClass : runnerMap.keySet()) {
					registerTask(host, taskClass);
				}
			}
		}
		lastUpdateTime = startUpdateTimeMilles;
	}

	/**
	 * 更新所有Croner的配置
	 */
	private List updateCronerConfig() {
		List list = taskAPI.getTaskCronerConfigList(taskProperties.getProject(), lastUpdateTime);
		if (list != null) {
			for (TaskCronerConfig tcc : list) {
				cronerConfigMap.put(tcc.getTaskClass(), tcc);
			}
		}
		return list;
	}

	/**
	 * 更新所有Runner的配置
	 */
	private List updateRunnerConfig() {
		List list = taskAPI.getTaskRunnerConfigList(taskProperties.getProject(), lastUpdateTime);
		if (list != null) {
			for (TaskRunnerConfig trc : list) {
				runnerConfigMap.put(trc.getTaskClass(), trc);
			}
		}
		return list;
	}

	/**
	 * 构建任务数据类型,并缓存
	 * 
	 * @param taskClass
	 * @param taskRunner
	 */
	private void constructTaskDataType(String taskClass, TaskRunner taskRunner) {
		Type interfaceType = taskRunner.getClass().getGenericInterfaces()[0];
		if (interfaceType instanceof ParameterizedType) {
			Type[] runnerTypes = ((ParameterizedType) interfaceType).getActualTypeArguments();
			JavaType[] paramTypes = new JavaType[runnerTypes.length];
			for (int i = 0; i < runnerTypes.length; i++) {
				if (runnerTypes[i] instanceof ParameterizedType) {
					ParameterizedType pt = ((ParameterizedType) runnerTypes[i]);
					System.out.println(pt.getActualTypeArguments());
					Type[] ts = pt.getActualTypeArguments();
					Class[] cs = new Class[ts.length];
					for (int x = 0; x < ts.length; x++) {
						cs[x] = (Class) ts[x];
					}
					paramTypes[i] = objectMapper.getTypeFactory().constructParametricType((Class) pt.getRawType(),
							cs);
				} else {
					paramTypes[i] = objectMapper.constructType(runnerTypes[i]);
				}
			}
			JavaType taskDataType = objectMapper.getTypeFactory().constructParametricType(TaskData.class, paramTypes);
			dataParamMap.put(taskClass, taskDataType);
		}
	}

	/**
	 * 注册单个任务
	 * 
	 * @param taskClass
	 */
	private void registerTask(String config, String taskClass) {
		if (log.isDebugEnabled()) {
			log.debug("开始注册任务{}......", taskClass);
		}
		TaskRunnerConfig runnerConfig = getRunnerConfig(taskClass);
		String queueName = taskClass + "$" + config;
		// 定义队列
		rabbitAdmin.declareQueue(new Queue(queueName, true));
		// 定义交换机
		rabbitAdmin.declareExchange(new DirectExchange(queueName + "@exchange", true, false));
		// 绑定
		rabbitAdmin.declareBinding(
				new Binding(queueName, DestinationType.QUEUE, queueName + "@exchange", queueName + "@route", null));
		// 启动任务监听器
		SimpleMessageListenerContainer factory = new SimpleMessageListenerContainer();
		factory.setConnectionFactory(connectionFactory);
		factory.setMaxConcurrentConsumers(runnerConfig.getConsumerNum());
		factory.setPrefetchCount(runnerConfig.getConsumerNum());
		factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
		factory.setQueueNames(queueName);
		MessageListenerAdapter listenerAdapter = new MessageListenerAdapter(taskConsumer, "process");
		listenerAdapter.setMessageConverter(new Jackson2JsonMessageConverter());
		// listenerAdapter.setReplyPostProcessor(new GZipPostProcessor());
		factory.setMessageListener(listenerAdapter);
		factory.setMessageConverter(new Jackson2JsonMessageConverter());
		factory.setAfterReceivePostProcessors(new GUnzipPostProcessor());
		factory.setAutoStartup(true);
		factory.afterPropertiesSet();
		factory.start();
		getContainerMap(config).put(taskClass, factory);
		if (log.isDebugEnabled()) {
			log.debug("完成注册并已启动任务{}监听......", taskClass);
		}
	}

	/**
	 * 根据配置名获得ContainerMap,如果没有则新建。
	 * 
	 * @param config
	 * @return
	 */
	private ConcurrentHashMap getContainerMap(String config) {
		ConcurrentHashMap map = runnerContainerMap.get(config);
		if (map == null) {
			map = new ConcurrentHashMap<>();
			runnerContainerMap.put(config, map);
		}
		return map;
	}

	/**
	 * 停止所有的任务。
	 */
	@PreDestroy
	private void stopAllTaskRunner() {
		for (ConcurrentHashMap map : runnerContainerMap.values()) {
			for (SimpleMessageListenerContainer container : map.values()) {
				container.stop();
			}
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy