mirror of
https://github.com/whyour/qinglong.git
synced 2026-08-05 16:25:04 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c32a53c40b | |||
| 8ae7a85bf8 | |||
| a56f2393a4 | |||
| 1124040eeb | |||
| f043aa62e4 | |||
| d64dc64df7 | |||
| c61d1aa828 | |||
| 33fa3aca99 | |||
| c772fc9527 |
@@ -164,7 +164,7 @@ jobs:
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=ref,event=branch,enable=${{ github.ref != format('refs/heads/{0}', 'master') }}
|
||||
type=ref,event=branch,enable=${{ github.ref == format('refs/heads/{0}', 'develop') }}
|
||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
|
||||
type=raw,value=${{ steps.version.outputs.version }},enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
@@ -176,6 +176,7 @@ export default (app: Router) => {
|
||||
path,
|
||||
`${originFilename.replace(/\//g, '')}`,
|
||||
);
|
||||
await fs.mkdir(path, { recursive: true });
|
||||
const filePath = join(path, `${filename.replace(/\//g, '')}`);
|
||||
const fileExists = await fileExist(filePath);
|
||||
if (fileExists) {
|
||||
|
||||
@@ -397,6 +397,21 @@ export function psTree(pid: number): Promise<number[]> {
|
||||
});
|
||||
}
|
||||
|
||||
export function isPidRunning(pid: number): boolean {
|
||||
// Validate PID: must be a positive integer
|
||||
if (pid == null || pid <= 0 || !Number.isInteger(pid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Signal 0 doesn't kill the process, just checks if it exists
|
||||
process.kill(pid, 0);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function killTask(pid: number) {
|
||||
const pids = await psTree(pid);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import { AuthDataType, SystemModel } from '../data/system';
|
||||
import SystemService from '../services/system';
|
||||
import UserService from '../services/user';
|
||||
import { writeFile, readFile } from 'fs/promises';
|
||||
import { createRandomString, fileExist, safeJSONParse } from '../config/util';
|
||||
import { createRandomString, fileExist, safeJSONParse, isPidRunning } from '../config/util';
|
||||
import OpenService from '../services/open';
|
||||
import { shareStore } from '../shared/store';
|
||||
import Logger from './logger';
|
||||
@@ -132,7 +132,32 @@ export default async () => {
|
||||
});
|
||||
|
||||
// 初始化更新所有任务状态为空闲
|
||||
await CrontabModel.update({ status: CrontabStatus.idle }, { where: {} });
|
||||
// 但保留仍在运行的任务的状态
|
||||
const allCrons = await CrontabModel.findAll({
|
||||
attributes: ['id', 'pid'],
|
||||
raw: true,
|
||||
});
|
||||
const idsToReset: number[] = [];
|
||||
|
||||
for (const cron of allCrons) {
|
||||
// 如果任务有 PID 且进程仍在运行,则保持其状态
|
||||
if (cron.pid != null && isPidRunning(cron.pid)) {
|
||||
// 保留当前状态(running 或 queued)
|
||||
continue;
|
||||
}
|
||||
// 收集需要重置的任务 ID
|
||||
if (cron.id) {
|
||||
idsToReset.push(cron.id);
|
||||
}
|
||||
}
|
||||
|
||||
// 批量更新所有需要重置的任务
|
||||
if (idsToReset.length > 0) {
|
||||
await CrontabModel.update(
|
||||
{ status: CrontabStatus.idle, pid: undefined },
|
||||
{ where: { id: { [Op.in]: idsToReset } } }
|
||||
);
|
||||
}
|
||||
|
||||
// 初始化时执行一次所有的 ql repo 任务
|
||||
CrontabModel.findAll({
|
||||
|
||||
@@ -107,7 +107,7 @@ export default class DependenceService {
|
||||
query: any = {},
|
||||
): Promise<Dependence[]> {
|
||||
let condition = query;
|
||||
if (DependenceTypes[type]) {
|
||||
if (type && DependenceTypes[type] !== undefined) {
|
||||
condition.type = DependenceTypes[type];
|
||||
}
|
||||
if (status) {
|
||||
|
||||
@@ -16,7 +16,7 @@ const SaveModal = ({
|
||||
|
||||
const handleOk = async (values: any) => {
|
||||
setLoading(true);
|
||||
const payload = { ...file, ...values, originFilename: file.title };
|
||||
const payload = { ...values, originFilename: file.title, content: file.content };
|
||||
request
|
||||
.post(`${config.apiPrefix}scripts`, payload)
|
||||
.then(({ code, data }) => {
|
||||
|
||||
+46
-9
@@ -1,10 +1,47 @@
|
||||
version: 2.19.2
|
||||
changeLogLink: https://t.me/jiao_long/431
|
||||
publishTime: 2025-06-27 23:59
|
||||
version: 2.20.0
|
||||
changeLogLink: https://t.me/jiao_long/432
|
||||
publishTime: 2025-12-10 01:05
|
||||
changeLog: |
|
||||
1. 备份数据支持选择模块,支持清除依赖缓存
|
||||
2. QLAPI 和 openapi 的 systemNotify 支持自定义通知类型和参数
|
||||
3. ntfy 增加可选的认证与用户动作,感谢 https://github.com/liheji
|
||||
4. 修复取消安装依赖
|
||||
5. 修复环境变量过大解析报错
|
||||
6. 修改服务启动方式
|
||||
1. 定时任务(cron / task)相关的大量修复 & 增强
|
||||
|
||||
修复 cron 解析错误(修复 parse cron / 升级 cron-parser)
|
||||
修复集群模式下定时任务可能不执行(race condition)
|
||||
定时任务支持订阅筛选
|
||||
定时任务支持排序调整
|
||||
定时任务支持自定义日志文件或无日志
|
||||
修复任务实例默认值
|
||||
任务支持单实例 / 多实例模式
|
||||
修复 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. 系统设置
|
||||
|
||||
新增多终端/多平台的并发登录会话支持
|
||||
Reference in New Issue
Block a user