一本书是怎么被写出来的 书架

第 07 章 / 共 10 章

第七章 · 30 秒轮询与早登记

写书 job 起跑时还不知道 slug——slug 是建筑师(写书 agent)中途起的。这一单要在中途就有了主人、能在 App 里看到「写书中」,服务端就得自己去把 slug 找出来。办法是一个 30 秒的轮询:setInterval 每 30 秒拿 jobId 去工作目录里反查 book.json。

这段代码在哪

它做什么

反查扫三个目录——WORKSPACE、BOOK_RUN_DIR(bookrun)、/tmp(旧约定):

async function findBookByJobId(jobId: string): Promise<{ dir: string; book: any } | null> {
  for (const root of [WORKSPACE, BOOK_RUN_DIR, "/tmp"]) {
    let dirs: string[];
    try {
      dirs = await readdir(root);
    } catch {
      continue;
    }
    for (const d of dirs) {
      try {
        const j = JSON.parse(await readFile(join(root, d, "book.json"), "utf8"));
        if (j?.jobId === jobId && typeof j?.slug === "string" && SLUG_RE.test(j.slug))
          return { dir: join(root, d), book: j };
      } catch {
        /* not a book dir */
      }
    }
  }
  return null;
}

每个目录尝试读 book.json,读到不是书目录(无此文件、JSON 坏、没 jobId)就跳过;命中要求三个条件同时成立:jobId 相等、slug 是字符串、且过 SLUG_RE(/^[a-z0-9][a-z0-9-]{0,62}$/——防提示词里被注入奇怪路径)。

轮询命中后做四件事:

  1. clearInterval——只登记一次。
  2. slug 回填 inflight 登记:续跑/放弃时省一次反查,也让 deploy.sh 的守卫清单能报出书名。
  3. 确定性兜底注入:type === "childrens" 且没写 hidden → 补 "hidden": true(绘本缺省不上架);没写 owner → 补下单人 scope。改完写回 book.json,日志 [book] injected defaults slug=… hidden=… owner=…。
  4. 早登记 bookmeta:往对话线 push 一条 {kind:"create", status:"running"} 条目,日志 [book] early-registered slug=… scope=…。
const reg = setInterval(async () => {
  try {
    const hit = await findBookByJobId(jobId);
    if (!hit) return;
    clearInterval(reg);
    const slug: string = hit.book.slug;
    earlySlug = slug;
    if (rec.slug !== slug) { rec.slug = slug; writeInflight(INFLIGHT_DIR, rec).catch(() => {}); }
    …
    const meta = (await readBookMeta(slug)) ?? { slug, scope, author, createdAt: startedAt, thread: [] };
    if (!meta.thread.some((e) => e.ts === startedAt)) {
      meta.thread.push({ ts: startedAt, kind: "create", instruction: seed.slice(0, 4000), …, status: "running" });
      await writeBookMeta(meta);
      console.log(`[book] early-registered slug=${slug} scope=${scope}`);
    }
  } catch {
    /* 下一轮再试 */
  }
}, 30000);
reg.unref?.();

为什么这样写

怎么排查

一本书是怎么被写出来的 · 王建硕
费曼式写法 · 由多个 AI 代理撰写与互相审校