Skip to content

service-queue: DbQueueAdapter.claimBatchpriority, scheduled_for 排序,而 sys_job_queue 的声明索引不含 priority —— 排序首键落空,恒定 1s 轮询每跳吃一次临时 B-tree 排序 #17612

Description

@os-litant

由分诊席在处理 #17610 时立卡 —— 该卡的维护者明确点名要这个判断:「service-queueDbQueueAdapter.claimBatch(默认 1s 轮询)按 priority, scheduled_for 排序,而声明索引是 ['queue','status','scheduled_for']——排序首键 priority 不在索引里;空闲时同样恒定轮询。你若判断应该另立卡,说出来。

判断:另立卡。 理由在下面「为什么不并进 #17610」。⛔ 未认领,⛔ 未定级 —— 本卡由分诊席开,domain:* 与优先级见分诊评论。

实测(origin/main @ 3ef96b47120a989d9333aeeeb6181bc371bc9b52)

维护者的两条读数逐条复现,⛔ 不是转述:

排序,packages/services/service-queue/src/db-queue-adapter.ts:478-487:

const candidates = await this.engine.find(QUEUE_TABLE, {
  where: { queue, status: 'pending' },
  limit: max * 3,                       // over-fetch in case of CAS contention
  orderBy: [
    { field: 'priority',      order: 'asc' },
    { field: 'scheduled_for', order: 'asc' },
  ],
  context: SYSTEM_CTX,
});

声明索引,packages/platform-objects/src/audit/sys-job-queue.object.ts:199-203:

indexes: [
  { fields: ['queue', 'status', 'scheduled_for'] },
  { fields: ['idempotency_key', 'queue'] },
  { fields: ['status'] },
],

QUEUE_TABLE = sys_job_queue(db-queue-adapter.ts:22)。

⇒ ⭐ 等值前缀 queue + status 能用上索引,但排序首键 priority 不在索引里 ⇒ 第三列 scheduled_for 对排序失效,引擎只能落到临时 B-tree 排序。⇒ 与 #17610 同形状:一个恒定轮询的领取查询,拿不到它以为拿得到的索引。

⭐ 为什么另立卡而不是并进 #17610

三条,任何一条单独成立即足够:

  1. 不同包、不同文件面。 service-messaging: NotificationDispatcher issues 32 statements per tick on an EMPTY outbox (reap runs per partition, twice) — idle cost scales with partitions × table size and never backs off #17610 的交付物在 packages/services/service-messaging(reap 解耦 + 空闲退避);本卡在 packages/services/service-queuepackages/platform-objects。同车道(domain:services)⛔ 不等于同一个 worktree、同一个 changeset。
  2. 不同修法。 service-messaging: NotificationDispatcher issues 32 statements per tick on an EMPTY outbox (reap runs per partition, twice) — idle cost scales with partitions × table size and never backs off #17610 修的是发多少条语句;本卡修的是一条语句多贵 —— 而且本卡的方向本身有分叉:把 priority 加进索引(索引变宽,写入变贵),还是把 priority 从排序里拿掉(改变领取顺序 = 行为变化)。⛔ 这不是能顺手带过的东西。
  3. 本卡的可测影响排在 driver-turso: remote mode never materializes object-level indexes — every declared secondary index is absent on production Turso tenant databases, so hot polling queries full-scan #17609 之后。 维护者在 driver-turso: remote mode never materializes object-level indexes — every declared secondary index is absent on production Turso tenant databases, so hot polling queries full-scan #17609 里实测:remote Turso 上 sys_job_queue 声明了 3 个索引、两个生产库里一个都没有。⇒ 今天在生产上,这张表根本没有索引可用不上 —— 「排序首键不在索引里」是 driver-turso: remote mode never materializes object-level indexes — every declared secondary index is absent on production Turso tenant databases, so hot polling queries full-scan #17609 落地之后才开始有代价的问题。

⚠️ ⇒ ⛔ 本卡不该在 #17609 之前派,否则验收无法在生产形态上测量。分诊评论会把这一条写成 Blocked-by:

Blocked-by: #17609

(⇒ remote 面上 sys_job_queue 今天一个声明索引都没有,本卡的验收在 #17609 落地前无法在生产形态上测量。)

范围

  1. 判定 priority 在领取路径上的地位:是真正的排序键(⇒ 索引要覆盖它),还是可以让位给 scheduled_for(⇒ 排序要改)。⛔ 这是行为判断,不是索引调优 —— 写清楚再动。
  2. 按第 1 条的结论,改索引声明或改 orderBy,两者同名同键地对齐。
  3. 空闲轮询:DbQueueAdapter 默认 1s 恒定轮询,与 service-messaging: NotificationDispatcher issues 32 statements per tick on an EMPTY outbox (reap runs per partition, twice) — idle cost scales with partitions × table size and never backs off #17610 的第 2 条验收(空闲退避)是同一个形状 —— ⚠️service-messaging: NotificationDispatcher issues 32 statements per tick on an EMPTY outbox (reap runs per partition, twice) — idle cost scales with partitions × table size and never backs off #17610 已落地一套退避机制,本卡应复用而非另写一套。
  4. 回归证据:领取查询在 remote 面上 EXPLAIN QUERY PLAN 不再出现 USE TEMP B-TREE FOR ORDER BY

⛔ 本卡不主张的

Refs: #17610(同形状的姊妹卡,维护者在其中点名要这个判断)· #17609(remote 索引缺失 —— 本卡的前置)· #17611(同一三件事叠乘里的第三张)


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions