zhizhi/scripts/bridge/check-queue.js

171 lines
5.9 KiB
JavaScript
Raw Permalink Normal View History

// 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); });