package cc.mrbird.febs.firewall.task;
|
|
import cc.mrbird.febs.common.utils.RedisUtils;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.stereotype.Component;
|
|
/**
|
* Nginx Reload 后台任务
|
* <p>
|
* 每 10 秒轮询 Redis 队列,有任务时执行 nginx reload。
|
* <p>
|
* 设计目的:
|
* 1. 避免 SpringBoot 直接调用系统命令
|
* 2. 支持批量合并 reload(多次修改只 reload 一次)
|
* 3. 防止误操作频繁 reload
|
*
|
* @author auto-generated
|
* @date 2026-07-31
|
*/
|
@Slf4j
|
@Component
|
@RequiredArgsConstructor
|
public class NginxReloadTask {
|
|
private final RedisUtils redisUtils;
|
|
/** Redis reload 任务队列 key */
|
private static final String NGINX_RELOAD_QUEUE_KEY = "firewall:nginx_reload_queue";
|
/** reload 脚本路径 */
|
private static final String RELOAD_SCRIPT = "/usr/local/bin/nginx_reload.sh";
|
/** Nginx 命令(备用) */
|
private static final String NGINX_CMD = "nginx -s reload";
|
|
/**
|
* 每 10 秒检查并消费 reload 队列
|
*/
|
@Scheduled(fixedDelay = 10_000)
|
public void checkAndReload() {
|
// 批量消费队列中所有待 reload 任务
|
int count = 0;
|
while (true) {
|
Object item = redisUtils.lGetIndex(NGINX_RELOAD_QUEUE_KEY, 0);
|
if (item == null) {
|
break;
|
}
|
count++;
|
redisUtils.lRemove(NGINX_RELOAD_QUEUE_KEY, 1, item);
|
log.info("消费 Nginx reload 任务: siteId={}", item);
|
}
|
|
if (count > 0) {
|
log.info("开始执行 Nginx reload (合并 {} 个任务)", count);
|
executeReload();
|
}
|
}
|
|
/**
|
* 执行 Nginx reload
|
* 优先使用 sudo 脚本,失败时回退到直接命令
|
*/
|
private void executeReload() {
|
// 方案1:通过 sudo 脚本执行(推荐,生产环境)
|
try {
|
Process process = Runtime.getRuntime().exec(new String[]{"sudo", RELOAD_SCRIPT});
|
process.waitFor();
|
if (process.exitValue() == 0) {
|
log.info("Nginx reload 成功 (via sudo script)");
|
return;
|
}
|
log.warn("Nginx reload 脚本执行返回非0: exitCode={}", process.exitValue());
|
} catch (Exception e) {
|
log.warn("Nginx reload 脚本执行失败,尝试直接命令: {}", e.getMessage());
|
}
|
|
// 方案2:直接执行 nginx reload(开发/测试环境)
|
try {
|
Process process = Runtime.getRuntime().exec(NGINX_CMD);
|
process.waitFor();
|
if (process.exitValue() == 0) {
|
log.info("Nginx reload 成功 (via direct command)");
|
} else {
|
log.error("Nginx reload 失败: exitCode={}", process.exitValue());
|
}
|
} catch (Exception e) {
|
log.error("Nginx reload 执行异常", e);
|
}
|
}
|
}
|