principle-separate-before-serializing-shared-state
先分离,再串行化共享状态
When concurrent actors might share mutable state, first ask whether they need the same mutable object. If not, eliminate the sharing. When sharing is real, enforce serialization structurally: lockfiles, sequential phases, exclusive ownership. Instructions and conventions are not concurrency control.
并发 actor 可能共享可变状态时,先问它们是否需要同一可变对象。不需要就消除共享。共享是真的,就用结构强制串行:锁文件、顺序阶段、独占所有权。文字指示和约定不是并发控制。
Why: Concurrent writes to shared state create race conditions that are intermittent, hard to reproduce, and expensive to debug.
为什么: 对共享状态的并发写会造成间歇、难复现、调试昂贵的竞态。
Pattern:
模式:
-
Identify shared mutable state (files both read and write, branches both push to, APIs both define and consume).
-
Default: eliminate the shared write target. Ask: do these actors need one canonical object, or are they publishing independent facts? Give each actor its own owned file, key, branch, or state directory, and merge only at the read/reporting boundary. Two workers writing their own
lastXfield into onestate.jsonis still shared mutation.indexer-state.json+metrics-state.jsonis not. -
Only when one shared write target is a real invariant, serialize access structurally (lockfiles, sequential phases, single-writer actor, or atomic compare-and-swap). Treat “we need a lock” as a design smell to check, not as the default answer.
-
识别共享可变状态(双方都读写的文件、双方都 push 的分支、双方都定义并消费的 API)。
-
默认:消除共享写目标。 问:这些 actor 需要一个规范对象,还是在发布独立事实?给每个 actor 自己拥有的文件、key、分支或状态目录,只在读/汇报边界合并。两个 worker 往同一个
state.json写各自的lastX字段,仍是共享变异。indexer-state.json+metrics-state.json不是。 -
只有单一共享写目标是真不变量时,才用结构串行访问(锁文件、顺序阶段、单写者 actor,或原子 compare-and-swap)。把「我们需要一把锁」当要检查的设计异味,不当默认答案。