/** * ★ 排队路径必须出声(2026-09-28 加) * * 为什么有这条判据:池满时邮件进 `queue`,而**排队路径此前一句日志都没有**。 * 于是「这封在排队」与「这封丢了」在日志上**完全同形** —— * 实测当天:发一封信,桥日志里那封 mail_id 一次都没出现, * 而它在库里已被 `markDelivered` 标成 read。 * 当时能给出的结论只有「不知道」。 * * 这条判据钉的是**形状**(源码里有入队/出队两声),不是读数 —— * 读数要真的把池压满才有,而那要 3 个真 worker。 */ import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; const HERE = dirname(fileURLToPath(import.meta.url)); const src = readFileSync(join(HERE, '..', 'src', 'pool.mjs'), 'utf8'); test('入队与出队各有一声,且都带 key', () => { const inQ = src.match(/log\(`排队 \$\{[^}]*\}/); assert.ok(inQ, '入队必须打日志(否则「在排队」与「丢了」同形)'); const outQ = src.match(/log\(`出队 \$\{[^}]*\}/); assert.ok(outQ, '出队必须打日志(否则不知道等了多久)'); }); test('★ 出队那一声要说出等了多久', () => { // 只打「出队」不够:知道排过队,但不知道等了 2 秒还是 20 分钟。 // 这正是当天「不知道」的一部分 —— 读数里没有时间维度。 assert.match(src, /enqueuedAt/, '入队时要记时间戳,否则算不出等待时长'); assert.match(src, /等了 \$\{waited/, '出队那一声必须包含等待时长'); }); test('入队那一声要带当前占用,否则事后无法判断是不是池满导致', () => { assert.match(src, /activeCount\(\)\}\/\$\{maxWorkers\}/, '入队日志必须带 activeCount/maxWorkers —— 区分「池满」与「别的原因」'); }); test('判据有分辨力:去掉入队日志 ⇒ 本组必须变红', () => { const stripped = src.replace(/log\(`排队 \$\{[\s\S]*?\}\);/, ''); assert.ok( !/log\(`排队/.test(stripped), '自检:删掉入队日志后源码里确实没有它 —— 否则这条判据恒绿' ); assert.notEqual(stripped, src, '自检:变异确实改动了东西'); });