Skip to content

Rust #325: try poll candidates in published PHP's fairness order - #895

Merged
rmcdaniel merged 1 commit into
mainfrom
rust-325-task-fairness
Nov 1, 2026
Merged

rmcdaniel merged 1 commit into
mainfrom
rust-325-task-fairness

Conversation

@rmcdaniel

Copy link
Copy Markdown
Member

Part of #325.

Contract (published Server 2.11.7, Workflow 2.15.7)

  • Batches. WorkflowTaskPoller::claimReadyTask and ActivityTaskPoller::claimReadyTask read a batch of candidates: limit max(10, max_tasks_per_poll * 10), 10 by default. The workflow bridge filters workflow types in SQL, and pages forward until a batch holds an eligible task.
  • Order. The poll tries the batch in TaskFairnessScheduler::reorder order:
    • tiers keep their priority order;
    • within a tier, the next candidate comes from the class with the fewest picks per unit of weight, ties going to the earliest-seen class;
    • tasks without a key share one default class.
  • State. The fairness state is InMemoryTaskFairnessState, which starts empty on every request of the Apache image. So only the batch's own picks count, and the first candidate never moves. The order decides which candidate a poll tries next when an earlier one can't be claimed.

Evidence. Raw worker HTTP against published 2.11.7, using a worker that can't replay typed search attributes:

  • ready tasks in time order were A1 (skipped), C (no key) and A2 (key a);
  • PHP claimed A2, then C. Time order would have claimed C.

Change

  • priority_fairness::fairness_order: the reorder, starting from empty state.
  • Store::fairness_batches: the claim loop drops candidates of an unsupported workflow type, as PHP's SQL does. It splits the rest into batches of 10 and tries each batch in that order.

Why no shared fixture

The skipped candidate in a recording is always a resume task, since a first task has no history to be skipped for. Published PHP gives resume tasks, and timer tasks, the default priority and no fairness key. That contradicts its own published inheritance rule (workflow_task => inherits_priority_and_fairness_from_parent_run), filed as durable-workflow/workflow#971. Native follows the rule, so the two servers place that task in different classes. With the same keys, native reproduced PHP's order.

Remaining

These are documented in the checkpoint:

  • PHP's activity poll stops after its first batch; native keeps looking.
  • Native's activity batches also hold other activity types, which PHP's SQL leaves out.

Checks

  • Unit tests. fairness_order pins the order: alternation, weights and tiers.
  • Native test. a_skipped_candidate_is_followed_by_another_fairness_class pins the claim path: A1 (a, skipped), A2 (a), B1 (b) gives B1, then A2.
  • Rust suites. Library 365 and integration 647, all passing.
  • Node unit suite. 6445 pass. The one failure is the known local PhpImageContextTest.

Checkpoint.

🤖 Generated with Claude Code

@rmcdaniel
rmcdaniel added this pull request to the merge queue Nov 1, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 1, 2026
Published PHP tries each batch of a poll's candidates (10 at the
default max_tasks_per_poll) in TaskFairnessScheduler order: within a
priority tier, fairness classes take turns by weight. Its fairness state
starts empty on every request of its Apache server, so the order never
moves a poll's first candidate. It decides which candidate a poll tries
next when an earlier one can't be claimed. Native now drops unsupported
workflow types as PHP's SQL does, and tries its candidates in the same
batches and order.

There is no shared fixture. The skipped candidate in a recording is a
resume task, and published PHP gives resume tasks no fairness key,
against its own inheritance contract (workflow#971). Native follows the
contract, so that task's class differs between the servers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rmcdaniel
rmcdaniel force-pushed the rust-325-task-fairness branch from 83fa8b1 to 2807d96 Compare November 1, 2026 03:51
@sonarqubecloud

sonarqubecloud Bot commented Nov 1, 2026

Copy link
Copy Markdown

@rmcdaniel
rmcdaniel added this pull request to the merge queue Nov 1, 2026
Merged via the queue into main with commit ec02369 Nov 1, 2026
58 checks passed
@rmcdaniel
rmcdaniel deleted the rust-325-task-fairness branch November 1, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant