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

com.github.javaclub.toolbox.AppBootHook Maven / Gradle / Ivy

/*
 * @(#)AppBootHook.java	2023-3-10
 *
 * Copyright (c) 2023. All Rights Reserved.
 *
 */

package com.github.javaclub.toolbox;

import static com.github.javaclub.toolbox.utils.ThreadLocalDateFormatter.parseNumericTimestamp;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.javaclub.AppBootConstants;
import com.github.javaclub.Constants.AppDefaultConfig;
import com.github.javaclub.toolbox.ToolBox.Collections;
import com.github.javaclub.toolbox.ToolBox.Environments;
import com.github.javaclub.toolbox.ToolBox.Maps;
import com.github.javaclub.toolbox.ToolBox.Numbers;
import com.github.javaclub.toolbox.ToolBox.Strings;
import com.github.javaclub.toolbox.ToolBox.Systems;
import com.github.javaclub.toolbox.cache.RedisStoreBuilder;
import com.github.javaclub.toolbox.cache.redis.RedisKeys;
import com.github.javaclub.toolbox.cache.redis.RedisStore;
import com.github.javaclub.toolbox.conf.CompositeAppConfigProperties;
import com.github.javaclub.toolbox.thread.ExecutorServiceInstance;
import com.github.javaclub.toolbox.utils.ThreadLocalDateFormatter;
import com.google.common.collect.Lists;

import redis.clients.jedis.Tuple;

/**
 * AppBootHook
 *
 * @author Gerald Chen
 * @version $Id: AppBootHook.java 2023-3-10 23:23:58 Exp $
 */
public class AppBootHook {
	
	static final Logger logger = LoggerFactory.getLogger(AppBootHook.class);
	
	private static volatile RedisStore redisStore;
	private static volatile AtomicBoolean shutdownFlag = new AtomicBoolean(false);

	public static void onStartup() {
		startWorks();
		registerMachineNode();
		Systems.showAppLogo();
		refreshAppRedisConfigProperties(
			"lastime.startup", ThreadLocalDateFormatter.timestampFormat(new Date())
		);
	}
	
	public static void onShutdown() {
		shutdownFlag.set(true);
		unregisterMachineNode();
		refreshAppRedisConfigProperties(
			"lastime.shutdown", ThreadLocalDateFormatter.timestampFormat(new Date())
		);
		clearWorks();
	}
	
	public static boolean isAppShuttingDown() {
		return null != shutdownFlag && shutdownFlag.get();
	}
	
	private static void startWorks() {
		CompositeAppConfigProperties.getInstance().getAppConfigProperties();
	}
	
	private static void clearWorks() {
		RedisStoreBuilder.destroyAll();
		// 先干其他的事情...,销毁本地App配置副本放在最后
		CompositeAppConfigProperties.getInstance().destroy();
	}
	
	static RedisStore getRedisStore() {
		if (null != redisStore) {
			return redisStore;
		}
		redisStore = RedisStore.defaultPublic();
		return redisStore;
	}

	private static void registerMachineNode() {
		String mnId = AppBootConstants.MACHINE_NODE_ID;
		RedisStore store = getRedisStore();
		if (null != store) {
			String key = AppBootConstants.getActiveServersRedisKey();
			ExecutorServiceInstance.get().scheduleAtFixedRate(() -> {
				if (shutdownFlag.get()) {
					logger.warn("Application【{}】is shutting down.", AppBootConstants.APP_NAME);
					return;
				}
				try {
					store.zadd(key, Double.valueOf(Numbers.getTimestampLong()), mnId);
				} catch (Throwable e) {
					logger.warn("RegisterMachineNode {} failed", mnId);
				}
				refreshLocalAppProperties(store);
			}, 1L, 30L, TimeUnit.SECONDS);
		}
	}

	private static void unregisterMachineNode() {
		String mnId = AppBootConstants.MACHINE_NODE_ID;
		RedisStore store = getRedisStore();
		if (null != store) {
			String key = AppBootConstants.getActiveServersRedisKey();
			try {
				store.zrem(key, Lists.newArrayList(mnId));
				refreshLocalAppProperties(store);
			} catch (Throwable e) {
				logger.warn("UnregisterMachineNode {} failed", mnId);
			}
		}
	}

	private static void refreshLocalAppProperties(RedisStore store) {
		String key = RedisKeys.custom("monitor").end("active_machines").build();
		try {
			Set set = store.zrangeByScoreWithScores(key, 0D, Double.valueOf(Numbers.getTimestampLong() + 100));
			List list = Lists.newArrayList();
			List zremHosts = Lists.newArrayList(); // 待清理删除的hosts
			if (Collections.isNotEmpty(set)) {
				set.forEach(t -> {
					long timestamp = new BigDecimal(t.getScore()).longValue();
					Date scoreDate = parseNumericTimestamp(String.valueOf(timestamp));
					if (null != scoreDate && (System.currentTimeMillis() - scoreDate.getTime() > 5*60*1000L)) { // 超过5分钟,无活跃信息的hosts自动删除
						zremHosts.add(t.getElement());
					} else {
						String str = Strings.concat(t.getElement(), "=", timestamp);
						list.add(str);
					}
				});
				Environments.setEnv(AppDefaultConfig.ENV_KEY_APP_MACHINES, list.toString());
				if (Collections.isNotEmpty(zremHosts)) {
					store.zrem(key, zremHosts);
				}
			}
		} catch (Throwable e) {
			// swallow ex
		}
	}
	
	private static void refreshAppRedisConfigProperties(String... keyvaluePair) {
		RedisStore store = getRedisStore(); // AppRedisConfig
		String rootKey = AppBootConstants.getCurrentAppNodeRedisConfKey();
		try {
			Map confMap = Maps.createStringMap(keyvaluePair);
			if (null != store && Maps.isNotEmpty(confMap)) {
				store.hmset(rootKey, confMap);
			}
		} catch (Throwable e) {
			// swallow ex
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy