Compare commits

...
Author SHA1 Message Date
copilot-swe-agent[bot]andwhyour bc92ba47f6 Fix IPv6 support by binding servers to '::' instead of '0.0.0.0'
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2026-01-29 11:39:08 +00:00
copilot-swe-agent[bot] dfb70abbe3 Initial plan 2026-01-29 11:27:05 +00:00
whyour d53437d169 更新 2.20.1 2025-12-26 21:17:30 +08:00
whyour d526602d19 修复运行中任务停止操作 2025-12-26 01:07:08 +08:00
whyour 91b44914f6 修复环境变量排序 2025-12-26 00:41:32 +08:00
5 changed files with 21 additions and 53 deletions
+6 -3
View File
@@ -29,7 +29,7 @@ import { logStreamManager } from '../shared/logStreamManager';
@Service() @Service()
export default class CronService { export default class CronService {
constructor(@Inject('logger') private logger: winston.Logger) {} constructor(@Inject('logger') private logger: winston.Logger) { }
private isNodeCron(cron: Crontab) { private isNodeCron(cron: Crontab) {
const { schedule, extra_schedules } = cron; const { schedule, extra_schedules } = cron;
@@ -165,7 +165,7 @@ export default class CronService {
let cron; let cron;
try { try {
cron = await this.getDb({ id }); cron = await this.getDb({ id });
} catch (err) {} } catch (err) { }
if (!cron) { if (!cron) {
continue; continue;
} }
@@ -467,7 +467,10 @@ export default class CronService {
for (const doc of docs) { for (const doc of docs) {
// Kill all running instances of this task // Kill all running instances of this task
try { try {
const command = this.makeCommand(doc); if (doc.pid) {
await killTask(doc.pid);
}
const command = doc.command.replace(/\s+/g, ' ').trim();
await killAllTasks(command); await killAllTasks(command);
this.logger.info( this.logger.info(
`[panel][停止所有运行中的任务实例] 任务ID: ${doc.id}, 命令: ${command}`, `[panel][停止所有运行中的任务实例] 任务ID: ${doc.id}, 命令: ${command}`,
+3 -2
View File
@@ -13,10 +13,11 @@ import {
stepPosition, stepPosition,
} from '../data/env'; } from '../data/env';
import { writeFileWithLock } from '../shared/utils'; import { writeFileWithLock } from '../shared/utils';
import { sequelize } from '../data';
@Service() @Service()
export default class EnvService { export default class EnvService {
constructor(@Inject('logger') private logger: winston.Logger) {} constructor(@Inject('logger') private logger: winston.Logger) { }
public async create(payloads: Env[]): Promise<Env[]> { public async create(payloads: Env[]): Promise<Env[]> {
const envs = await this.envs(); const envs = await this.envs();
@@ -146,7 +147,7 @@ export default class EnvService {
} }
try { try {
const result = await this.find(condition, [ const result = await this.find(condition, [
['isPinned', 'DESC'], [sequelize.literal('COALESCE(`isPinned`, 0)'), 'DESC'],
['position', 'DESC'], ['position', 'DESC'],
['createdAt', 'ASC'], ['createdAt', 'ASC'],
]); ]);
+1 -1
View File
@@ -25,7 +25,7 @@ export class GrpcServerService {
const grpcPort = config.grpcPort; const grpcPort = config.grpcPort;
const bindAsync = promisify(this.server.bindAsync).bind(this.server); const bindAsync = promisify(this.server.bindAsync).bind(this.server);
await bindAsync( await bindAsync(
`0.0.0.0:${grpcPort}`, `[::]:${grpcPort}`,
ServerCredentials.createInsecure(), ServerCredentials.createInsecure(),
); );
Logger.debug(`✌️ gRPC service started successfully`); Logger.debug(`✌️ gRPC service started successfully`);
+1 -1
View File
@@ -11,7 +11,7 @@ export class HttpServerService {
async initialize(expressApp: express.Application, port: number) { async initialize(expressApp: express.Application, port: number) {
try { try {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.server = expressApp.listen(port, '0.0.0.0', () => { this.server = expressApp.listen(port, '::', () => {
Logger.debug(`✌️ HTTP service started successfully`); Logger.debug(`✌️ HTTP service started successfully`);
metricsService.record('http_service_start', 1, { metricsService.record('http_service_start', 1, {
port: port.toString(), port: port.toString(),
+10 -46
View File
@@ -1,47 +1,11 @@
version: 2.20.0 version: 2.20.1
changeLogLink: https://t.me/jiao_long/432 changeLogLink: https://t.me/jiao_long/433
publishTime: 2025-12-10 01:05 publishTime: 2025-12-26 22:00
changeLog: | changeLog: |
1. 定时任务(cron / task)相关的大量修复 & 增强 1. 修复获取依赖管理列表
2. notify.js 修复 TG_PROXY_AUTH 参数拼接
修复 cron 解析错误(修复 parse cron / 升级 cron-parser 3. QLAPI.notify larkSecret 参数
修复集群模式下定时任务可能不执行(race condition 4. 修复 cron parser 定时规则校验
定时任务支持订阅筛选 5. 修复设置 baseUrl 后无法访问
定时任务支持排序调整 6. 修复环境变量排序
定时任务支持自定义日志文件或无日志 7. 修复定时任务无法停止
修复任务实例默认值
任务支持单实例 / 多实例模式
修复 task 命令软链可能失败问题
2. 日志系统相关的大更新
修复日志目录逻辑
修复 pm2 日志目录
优化日志写入(stream pooling
3. 环境变量(env)系统的改进与修复
修复环境变量复制到剪贴板时可能失败
添加环境变量“置顶”功能
修复 QlPort 与 QlGrpcPort 环境变量在 host network 模式下被忽略
增加全局 SSH 私钥配置
4. Docker / 非 root 用户 / Alpine 兼容性增强
新增非 root Docker 用户支持,自动初始化命令
修复 Alpine 容器 DNS 解析失败(设置 ndots:0
修复 PM2 在 ARM 路由器(Node.js 不兼容)上的启动失败
移除 nginx(可能是考虑更轻量的镜像运行)
5. API 安全与校验增强
Dependencies GET endpoint 增加校验
Script API routes 增加输入校验
修复 JWT 认证问题
Feishu 机器人通知增加签名校验
QLAPI 增加 cron task 管理功能
修复 URIError(错误 cookie 导致白屏)
6. 系统设置
新增多终端/多平台的并发登录会话支持