一、目的
- 服务发生线程锁住,需要下线服务时,保证请求中的接口不受影响,执行完后,再下线服务
二、步骤
*kill -15时执行改钩子函数 优雅停机
1.当线程锁住
2.运维那边监控到,然后进行kill -15 进程ID
3.代码这边监听到关闭信号,先把容器权重设置为0,不允许新的请求进来.
4.然后为了保住容器其他请求中的接口不受影响,进行睡眠30s再关闭容器
三、代码实现
package com.dst.XXX.XXX;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.dst.steed.common.util.DstSpringUtil;
import com.dst.steed.rabbit.annotation.SteedAmqpScan;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StopWatch;
import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import static com.dst.lcb.base.DstSteedLcbBaseService.PACKAGE_NAME;
/**
* 服务启动
*
* @author LWP
* @since 2024/08/20
*/
@Slf4j
@SpringBootApplication(scanBasePackages = {PACKAGE_NAME})
@EnableFeignClients(basePackages = PACKAGE_NAME + ".infrastructure.acl")
@MapperScan(basePackages = {PACKAGE_NAME + ".infrastructure.biz.**.mapper", PACKAGE_NAME + ".modules.mapper","generator.mapper"})
@SteedAmqpScan(basePackage = PACKAGE_NAME + ".infrastructure.mq")
public class DstSteedXXXXService implements CommandLineRunner, ApplicationContextAware {
public static final String PACKAGE_NAME = "com.dst.XXX.XXX";
@Autowired
private ConfigurableApplicationContext applicationContext;
@Resource
private NacosDiscoveryProperties nacosDiscoveryProperties;
public static void main(String[] args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
SpringApplication.run(DstSteedLcbBaseService.class, args);
stopWatch.stop();
log.info("【服务:" + DstSpringUtil.getAppName() +
";环境:" + DstSpringUtil.getActiveProfile() +
"】启动成功,耗时:" +
new DecimalFormat("#.##").format(stopWatch.getTotalTimeSeconds()) + " 秒。");
}
/**
* kill -15时执行改钩子函数 优雅停机
* 1.线程锁住
* 2.运维那边监控到,然后进行kill -15 进程ID
* 3.代码这边监听到关闭信号,先把容器权重设置为0,不允许新的请求进来.
* 4.然后为了保住容器其他请求中的接口不受影响,进行睡眠30s再关闭容器
*/
@Override
public void run(String... args) {
log.info("启动成功 !");
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("收到服务关闭信号");
stop();
try {
log.info("睡眠30秒");
Thread.sleep(30000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
applicationContext.close();
}));
}
private void stop() {
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.NAMESPACE, nacosDiscoveryProperties.getNamespace());
properties.put(PropertyKeyConst.SERVER_ADDR, nacosDiscoveryProperties.getServerAddr());
NamingService namingService = NacosFactory.createNamingService(properties);
String serviceName = nacosDiscoveryProperties.getService();
List<Instance> instanceList = namingService.getAllInstances(serviceName);
Optional<Instance> currentInstance = instanceList.stream()
.filter(instance -> instance.getIp().equals(nacosDiscoveryProperties.getIp()))
.findFirst();
currentInstance.ifPresent(instance -> {
log.info("找到当前服务实例: {}", instance);
instance.setWeight(0);
try {
namingService.registerInstance(serviceName, instance);
log.info("Nacos 服务权重已设置为 0");
} catch (NacosException e) {
log.error("设置 Nacos 服务权重时发生错误", e);
}
});
} catch (NacosException e) {
log.error("获取 Nacos 命名服务时发生错误", e);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext instanceof ConfigurableApplicationContext) {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
}
}