concurrent-observable-state-updates
について
このスキルは、複数の並行スレッドから観測可能な状態を安全に更新し、信頼性の高いイベント配信を保証するためのパターンを提供します。単調増加するバージョン番号とアトミックな比較交換操作を使用することで、古い状態の上書き、イベントの欠落、デッドロックといった問題に対処します。開発者は、複数のスレッドが共有状態を変更し、オブザーバブルに通知する場合、特に並行処理に関連するイベント損失や状態破損に直面している際に、このパターンを使用すべきです。
クイックインストール
Claude Code
推奨/plugin add https://github.com/majiayu000/claude-skill-registrygit clone https://github.com/majiayu000/claude-skill-registry.git ~/.claude/skills/concurrent-observable-state-updatesこのコマンドをClaude Codeにコピー&ペーストしてスキルをインストールします
ドキュメント
Concurrent Observable State Updates
Problem
When multiple threads update shared state and publish to observables (reactive values, UI state, etc.), several concurrency bugs can occur:
- Stale overwrites: Thread A reads state, Thread B updates and publishes newer state, then Thread A publishes its stale snapshot, overwriting B's correct state
- Event drops: Using version numbers to skip stale state updates also skips the associated events, losing notifications of things that actually happened
- Lock order inversion: Taking a version/state mutex before a frame/transaction lock creates deadlock risk with code paths that hold frame lock first
- Frame incoherence: Events and state updates in separate frames cause subscribers to see inconsistent snapshots
Context / Trigger Conditions
- Multiple worker threads completing tasks and updating shared state
- FRP/reactive systems where state changes trigger observable updates
- Worker pools, task queues, or concurrent job processors
- Symptoms: missing events, state showing older values, occasional deadlocks
Solution
1. Use Monotonic Version Numbers
Add a version counter to your state that increments on every mutation:
structure State where
data : ...
version : Nat := 0 -- Monotonically increasing
Every atomic state mutation must increment the version:
atomically do
let newVersion := state.version + 1
let newState := { state with ..., version := newVersion }
set newState
return (newState, newVersion)
2. Separate Event Firing from State Version Checks
Critical insight: Events represent things that happened and must NEVER be dropped. Version checks should only gate observable/state updates, not events.
let updateWithEvent := fun (state, version, fireEvent) =>
withFrame do
-- ALWAYS fire events first - they happened, notify subscribers
fireEvent
-- THEN check version for state updates only
let shouldUpdateState ← versionMutex.atomically do
if version > lastPublishedVersion then
set version
return true
else
return false
if shouldUpdateState then
updateObservables state
3. Consistent Lock Ordering
Always acquire frame/transaction lock BEFORE any other mutexes:
-- CORRECT: Frame lock first, then version mutex inside
withFrame do
fireEvent
versionMutex.atomically do ... -- Brief, inside frame
-- WRONG: Version mutex first creates lock inversion risk
versionMutex.atomically do ...
withFrame do ... -- Can deadlock with code already in frame
4. Atomic State Modifications Return New State
Don't read state separately from modifying it - return the new state from the atomic block:
-- CORRECT: Modification returns the state to publish
let (newState, version) ← stateMutex.atomically do
let modified := { currentState with ... }
set modified
return (modified, modified.version)
publishState newState version
-- WRONG: Separate read can see other threads' changes
stateMutex.atomically do modify ...
let state ← stateMutex.atomically do get -- May include other changes!
publishState state
Verification
- No event drops: Every completed operation fires its event, even if state update is skipped
- Monotonic state: Observable state version never decreases
- No deadlocks: All code paths acquire locks in same order (frame → version)
- Eventually consistent: Final observable state matches final mutex state
Example
Worker pool with concurrent job completions:
-- Worker completes job
let (newState, version) ← stateMutex.atomically do
if generation == expectedGeneration then
let state' := { state with
running := state.running.erase jobId,
statuses := state.statuses.insert jobId .completed,
version := state.version + 1
}
set state'
return some (state', state'.version)
else
return none
match result with
| some (state, ver) =>
-- Frame first, then version check inside
withFrame do
-- Always fire completion event
fireCompleted (jobId, result)
-- Only update observables if latest version
let shouldUpdate ← versionMutex.atomically do
if ver > lastPublished then
set ver; return true
else return false
if shouldUpdate then
updateJobStates state.statuses
updateCounts state.pending.size state.running.size
| none => pure ()
Notes
- Trade-off: When an event fires, observable state might not yet reflect that event if a newer version was already published. But events carry complete data, so subscribers have what they need.
- State is eventually consistent: The latest state will be published; only intermediate stale states are skipped.
- Events are point-in-time: They represent discrete occurrences, so they must always fire.
- Observables are latest-value: They represent current state, so stale values should be skipped.
Anti-patterns
- Skipping events with state:
if versionOk then { updateState; fireEvent }loses events - Lock inversion: Taking state/version mutex before frame lock
- Separate state reads: Reading state in one atomic block, publishing in another
- Blocking in frame: Holding frame lock while doing slow operations
GitHub リポジトリ
関連スキル
algorithmic-art
メタThis Claude Skill creates original algorithmic art using p5.js with seeded randomness and interactive parameters. It generates .md files for algorithmic philosophies, plus .html and .js files for interactive generative art implementations. Use it when developers need to create flow fields, particle systems, or other computational art while avoiding copyright issues.
subagent-driven-development
開発This skill executes implementation plans by dispatching a fresh subagent for each independent task, with code review between tasks. It enables fast iteration while maintaining quality gates through this review process. Use it when working on mostly independent tasks within the same session to ensure continuous progress with built-in quality checks.
executing-plans
デザインUse the executing-plans skill when you have a complete implementation plan to execute in controlled batches with review checkpoints. It loads and critically reviews the plan, then executes tasks in small batches (default 3 tasks) while reporting progress between each batch for architect review. This ensures systematic implementation with built-in quality control checkpoints.
cost-optimization
その他This Claude Skill helps developers optimize cloud costs through resource rightsizing, tagging strategies, and spending analysis. It provides a framework for reducing cloud expenses and implementing cost governance across AWS, Azure, and GCP. Use it when you need to analyze infrastructure costs, right-size resources, or meet budget constraints.
