guanghulab/scripts/bridge/check-queue.js
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

171 lines
5.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// scripts/bridge/check-queue.js
// 🌉 桥接·调度队列检查
//
// 查询 Notion 调度队列数据库中指定类型+状态的任务
// 用法: node scripts/bridge/check-queue.js [BROADCAST_READY|SYSLOG_RECEIVED|HEARTBEAT]
//
// 环境变量:
// NOTION_TOKEN Notion API token
// BRIDGE_QUEUE_DB_ID 桥接调度队列数据库 ID
'use strict';
const https = require('https');
const fs = require('fs');
const path = require('path');
const NOTION_VERSION = '2022-06-28';
const NOTION_API_HOSTNAME = 'api.notion.com';
// ══════════════════════════════════════════════════════════
// Notion API 基础调用
// ══════════════════════════════════════════════════════════
function notionPost(endpoint, body, token) {
return new Promise((resolve, reject) => {
const payload = JSON.stringify(body);
const opts = {
hostname: NOTION_API_HOSTNAME,
port: 443,
path: endpoint,
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json',
'Notion-Version': NOTION_VERSION,
'Content-Length': Buffer.byteLength(payload),
},
};
const req = https.request(opts, res => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(data);
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(parsed);
} else {
reject(new Error(`Notion API ${res.statusCode}: ${parsed.message || data}`));
}
} catch (e) {
reject(new Error(`Notion API parse error: ${data}`));
}
});
});
req.on('error', reject);
req.write(payload);
req.end();
});
}
// ══════════════════════════════════════════════════════════
// 主逻辑
// ══════════════════════════════════════════════════════════
async function checkQueue(taskType) {
const token = process.env.NOTION_TOKEN;
const dbId = process.env.BRIDGE_QUEUE_DB_ID;
if (!token) {
console.log('⚠️ 缺少 NOTION_TOKEN跳过调度队列检查');
process.exit(0);
}
if (!dbId) {
console.log('⚠️ 缺少 BRIDGE_QUEUE_DB_ID跳过调度队列检查');
process.exit(0);
}
console.log(`🌉 检查调度队列 · 类型=${taskType} · 状态=待处理`);
const filter = {
and: [
{ property: '类型', select: { equals: taskType } },
{ property: '处理状态', status: { equals: '待处理' } },
],
};
const body = {
filter,
sorts: [{ property: '创建时间', direction: 'ascending' }],
page_size: 50,
};
try {
const result = await notionPost(`/v1/databases/${dbId}/query`, body, token);
const tasks = result.results || [];
console.log(`📋 发现 ${tasks.length} 条待处理任务`);
// 将任务列表写入临时文件供后续步骤使用
const outputDir = path.join('data', 'bridge-logs');
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const outputFile = path.join(outputDir, `queue-${taskType.toLowerCase()}-${Date.now()}.json`);
const taskSummaries = tasks.map(t => ({
id: t.id,
task_name: extractTitle(t),
task_type: taskType,
dev_id: extractSelect(t, 'DEV编号'),
broadcast_id: extractRichText(t, '广播编号'),
source: extractRichText(t, '来源渠道'),
payload: extractRichText(t, 'Payload'),
created_time: t.created_time,
}));
fs.writeFileSync(outputFile, JSON.stringify(taskSummaries, null, 2));
console.log(`📁 任务列表已写入: ${outputFile}`);
// 输出到 GITHUB_OUTPUT供 workflow 使用)
if (process.env.GITHUB_OUTPUT) {
fs.appendFileSync(process.env.GITHUB_OUTPUT,
`task_count=${tasks.length}\n` +
`queue_file=${outputFile}\n`
);
}
return taskSummaries;
} catch (e) {
console.error(`❌ 查询调度队列失败: ${e.message}`);
process.exit(1);
}
}
// ══════════════════════════════════════════════════════════
// Notion 属性提取辅助
// ══════════════════════════════════════════════════════════
function extractTitle(page) {
const prop = page.properties && page.properties['任务名称'];
if (prop && prop.title && prop.title.length > 0) {
return prop.title.map(t => t.plain_text).join('');
}
return '';
}
function extractSelect(page, name) {
const prop = page.properties && page.properties[name];
if (prop && prop.select) {
return prop.select.name || '';
}
return '';
}
function extractRichText(page, name) {
const prop = page.properties && page.properties[name];
if (prop && prop.rich_text && prop.rich_text.length > 0) {
return prop.rich_text.map(t => t.plain_text).join('');
}
return '';
}
// ══════════════════════════════════════════════════════════
// 入口
// ══════════════════════════════════════════════════════════
const taskType = process.argv[2] || 'BROADCAST_READY';
checkQueue(taskType).catch(e => { console.error(e); process.exit(1); });