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
}
}
}