Skip to content
预计 1 分钟右侧目录可快速定位

数据库并发边界:Transaction、Isolation、Optimistic Concurrency 与 Pool ​

前置:Runtime 数据库怎样设计 Key 和 Index:Schema、Key 与 Index
核心问题:两个 Worker 同时更新同一 Run 时,数据库怎样阻止 lost update,又怎样避免用过重锁把吞吐拖垮?

先在短事务里 claim node,提交后调用外部 Tool;完成再开新事务写 result。两个 worker claim 同一 READY node,用 UPDATE ... WHERE status=READY 的影响行数决定谁成功。

Transaction ​

transaction 提供原子性/隔离,但只覆盖同一数据库资源。隔离级别决定并发可见性与冲突,不要长期持锁等待 LLM/HTTP。Transaction 让同一数据库中的多步写入满足原子提交/回滚,但不要跨慢 LLM/HTTP 调用长期持有事务,否则锁和连接被占用。

长事务会占连接和锁,不应等待外部 Agent 操作。

Isolation 基础 ​

Isolation 解决并发事务彼此能看到什么、冲突时谁可以提交。Harness 最常见的问题不是背四种隔离级别,而是避免两个 Worker 同时把同一个 Run 当成自己拥有。

例如:

text
worker A reads version=7
worker B reads version=7
A UPDATE ... WHERE version=7 → success, version=8
B UPDATE ... WHERE version=7 → 0 rows → conflict

这种短事务 + optimistic concurrency 通常比把整个长 Run 放在高隔离事务里更合理。长时间持锁会让 Agent 的网络/模型等待直接拖垮数据库。

Optimistic Concurrency ​

用 version/updated at compare-and-swap 检测并发更新,适合低冲突 RunState;冲突后重新加载/合并而非覆盖。

通过 version/etag 条件更新检测并发冲突,适合状态记录读多写少、冲突可重试。冲突意味着要重新读取事实,而不是覆盖。

Database Connection Pool ​

增加并行度最终受 provider quota、DB pool、CPU、网络限制。bounded queue/backpressure 让上游在系统饱和时减速,而非继续制造内存任务。

数据库 Connection Pool 是昂贵 DB session 的容量边界。Agent 的 coroutine 数通常远大于连接数,因此要控制事务持有时间、acquire timeout 和 per-DB concurrency,尤其不能跨模型/HTTP await 长时间占连接。

两个 Worker 同时 Resume 一个 Run 会发生什么 ​

假设 worker A、B 都读到:

text
run_id=r-42, status=READY, version=17

如果两边随后都直接 UPDATE runs SET status='RUNNING',就可能同时认为自己拿到了执行权。一个简单的 optimistic claim 可以是:

sql
UPDATE runs
SET status = 'RUNNING', version = 18, owner_id = :worker
WHERE run_id = 'r-42'
  AND status = 'READY'
  AND version = 17;

只有 rowcount == 1 的 worker 获得 claim;另一个必须重新读取状态。也可以使用数据库锁或 queue/lease 方案,但目标相同:并发控制要把“谁拥有执行权”变成数据库能证明的事实。

Transaction isolation 决定并发事务能观察到什么,但不会自动替你设计 Run ownership。隔离级别、optimistic version、unique constraint、lease/fencing 分别解决不同层的问题。

Failure Modes ​

数据库 Transaction 中等待长 LLM/HTTP ​

症状: begin 后调用模型/远程 Tool 数十秒再提交。

为什么危险: 连接和锁长期占用。

处理: 事务只覆盖短本地修改;外部动作通过状态机/outbox/execution record 协调。

如何验证 ​

Case断言
数据库 Transaction 中等待长 LLM/HTTP外部调用慢 10x,DB transaction duration 仍保持短。

自测 ​

  1. 两个 Worker 同时把同一个 Run 从 WAITING 更新到 RUNNING。怎样用 transaction/version check 避免 lost update?
  2. 连接池耗尽与数据库行锁等待都会让请求变慢,如何从等待位置区分这两种瓶颈?

Sources ​

AI Engineering · Agent · Harness · Backend Systems