Skip to content

feat(effect): add stepOne() to ControlledScheduler for fine-grained task execution#6168

Open
copyleftdev wants to merge 2 commits intoEffect-TS:next-minorfrom
copyleftdev:fix/controlled-scheduler-stepOne
Open

feat(effect): add stepOne() to ControlledScheduler for fine-grained task execution#6168
copyleftdev wants to merge 2 commits intoEffect-TS:next-minorfrom
copyleftdev:fix/controlled-scheduler-stepOne

Conversation

@copyleftdev
Copy link
Copy Markdown

Problem

ControlledScheduler.step() drains all pending tasks across all priority buckets in a single call:

step() {
  const tasks = this.tasks.buckets
  this.tasks.buckets = []          // takes everything
  for (const [_, toRun] of tasks)  // runs everything
    for (let i = 0; i < toRun.length; i++)
      toRun[i]()
}

There is no way to execute exactly one task and observe the intermediate state. This makes it impossible to reproduce concurrency bugs in a controlled environment — you can't step through individual task interleavings to find the specific ordering that triggers the issue.

Relevant bugs that are hard to reproduce without fine-grained stepping:

Fix

Add stepOne() to ControlledScheduler:

stepOne(): boolean {
  const buckets = this.tasks.buckets
  for (let i = 0; i < buckets.length; i++) {
    const [_, tasks] = buckets[i]!
    if (tasks.length > 0) {
      const task = tasks.shift()!
      if (tasks.length === 0) buckets.splice(i, 1)
      task()
      return true
    }
  }
  return false
}
  • Executes exactly one task from the highest-priority bucket
  • Returns true if a task was executed, false if empty
  • step() behavior unchanged
  • 1 file, 15 lines added, purely additive

Test plan

  • Schedule.test.ts — 82 tests pass
  • Effect/scheduling.test.ts — 2 tests pass
  • Fiber.test.ts — 16 tests pass
  • Zero regressions

🤖 Generated with Claude Code

…ask execution

ControlledScheduler.step() drains ALL pending tasks across all priority
buckets in a single call. There is no way to execute exactly one task
and observe the state between executions.

This makes it impossible to reproduce concurrency bugs like Effect-TS#6081
(semaphore race condition) or Effect-TS#6014 (workflow deadlock during replay)
in a controlled environment — you can't step through individual task
interleavings to find the ordering that triggers the bug.

Add stepOne() which executes exactly one task from the highest-priority
bucket and returns. This is the primitive needed for deterministic
simulation testing where each scheduling decision must be individually
controllable.

- step() behavior unchanged (drains all)
- stepOne() executes one, returns boolean
- 15 lines of code, additive only

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-project-automation github-project-automation bot moved this to Discussion Ongoing in PR Backlog Apr 12, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 12, 2026

🦋 Changeset detected

Latest commit: 2854878

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 36 packages
Name Type
effect Minor
@effect/cli Major
@effect/cluster Major
@effect/experimental Major
@effect/opentelemetry Major
@effect/platform-browser Major
@effect/platform-bun Major
@effect/platform-node-shared Major
@effect/platform-node Major
@effect/platform Major
@effect/printer-ansi Major
@effect/printer Major
@effect/rpc Major
@effect/sql-clickhouse Major
@effect/sql-d1 Major
@effect/sql-drizzle Major
@effect/sql-kysely Major
@effect/sql-libsql Major
@effect/sql-mssql Major
@effect/sql-mysql2 Major
@effect/sql-pg Major
@effect/sql-sqlite-bun Major
@effect/sql-sqlite-do Major
@effect/sql-sqlite-node Major
@effect/sql-sqlite-react-native Major
@effect/sql-sqlite-wasm Major
@effect/sql Major
@effect/typeclass Major
@effect/vitest Major
@effect/workflow Major
@effect/ai Major
@effect/ai-amazon-bedrock Major
@effect/ai-anthropic Major
@effect/ai-google Major
@effect/ai-openai Major
@effect/ai-openrouter Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@effect-bot effect-bot changed the base branch from main to next-minor April 12, 2026 03:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Discussion Ongoing

Development

Successfully merging this pull request may close these issues.

2 participants