Skip to content

fix: cancel in progress has incorrect ordering with new in-memory index#4442

Merged
abelanger5 merged 9 commits into
mainfrom
belanger/concurrency-cancel-in-progress-fix
Jul 16, 2026
Merged

fix: cancel in progress has incorrect ordering with new in-memory index#4442
abelanger5 merged 9 commits into
mainfrom
belanger/concurrency-cancel-in-progress-fix

Conversation

@abelanger5

@abelanger5 abelanger5 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Description

When SERVER_CONCURRENCY_IN_MEMORY_INDEX_ENABLED=true is set (enabling the new experimental in-memory index), the cancel-in-progress concurrency strategy incorrectly acts like cancel-newest. This is due to the comparator method for the internal heap using the default priorityCompare instead of ranking newer slots as greater values in the heap, so they take precedence when popping out of the minHeap.

Also adds a set of Python tests which use task-level concurrency for cancel-in-progress and cancel-newest, which correctly failed when setting SERVER_CONCURRENCY_IN_MEMORY_INDEX_ENABLED.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

What's Changed

  • New unit, integration and e2e tests to ensure we catch this path
  • Adding a new comparator for CancelInProgress

Checklist

Changes have been:

  • Tested (unit, integration, or manually with steps specified)
  • Linted and formatted

🤖 AI Disclosure
  • I acknowledge that an LLM was used in the creation of this Pull Request, in accordance with Hatchet's AI_POLICY.md.
  • Details: Claude w/ Fable

@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hatchet-docs Ready Ready Preview, Comment Jul 16, 2026 5:15pm

Request Review

@github-actions github-actions Bot added the github_actions Pull requests that update GitHub Actions code label Jul 16, 2026
@github-actions github-actions Bot added the sdk-py Related to the Python sdk label Jul 16, 2026
@github-actions github-actions Bot added the engine Related to the core Hatchet engine label Jul 16, 2026
@abelanger5 abelanger5 changed the title (wip) cancel in progress bug on new in-memory index fix: cancel in progress has incorrect ordering with new in-memory index Jul 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Optional test failure: The load-deadlock job failed on this PR (optimistic-scheduling=true). This check is non-mandatory and does not block merging, but may be worth investigating. View logs

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Benchmark results

goos: linux
goarch: amd64
pkg: github.com/hatchet-dev/hatchet/pkg/scheduling/v1
cpu: AMD Ryzen 9 7950X3D 16-Core Processor          
                                         │ /tmp/old.txt │            /tmp/new.txt            │
                                         │    sec/op    │    sec/op     vs base              │
RateLimiter-8                              59.93µ ± 11%   61.53µ ± 40%       ~ (p=0.485 n=6)
Scheduler_Replenish_DenseSharedActions-8   14.50m ±  5%   13.78m ±  2%  -4.96% (p=0.004 n=6)
geomean                                    932.1µ         920.7µ        -1.22%

                                         │ /tmp/old.txt │            /tmp/new.txt            │
                                         │     B/op     │     B/op      vs base              │
RateLimiter-8                              137.7Ki ± 0%   137.7Ki ± 0%       ~ (p=0.509 n=6)
Scheduler_Replenish_DenseSharedActions-8   11.69Mi ± 0%   11.69Mi ± 0%  +0.02% (p=0.002 n=6)
geomean                                    1.254Mi        1.254Mi       +0.01%

                                         │ /tmp/old.txt │            /tmp/new.txt             │
                                         │  allocs/op   │  allocs/op   vs base                │
RateLimiter-8                               1.022k ± 0%   1.022k ± 0%       ~ (p=1.000 n=6) ¹
Scheduler_Replenish_DenseSharedActions-8    17.46k ± 0%   17.52k ± 0%  +0.38% (p=0.002 n=6)
geomean                                     4.224k        4.232k       +0.19%
¹ all samples are equal

pkg: github.com/hatchet-dev/hatchet/pkg/scheduling/v1/concurrency
                                        │ /tmp/old.txt │            /tmp/new.txt            │
                                        │    sec/op    │    sec/op     vs base              │
ConcurrencyThroughput/wal/batch=100-8      2.279 ±  1%    2.310 ±  2%       ~ (p=0.065 n=6)
ConcurrencyThroughput/wal/batch=1000-8    291.4m ±  2%   277.6m ±  2%  -4.73% (p=0.002 n=6)
ConcurrencyThroughput/wal/batch=10000-8   55.63m ±  9%   52.57m ±  3%  -5.50% (p=0.041 n=6)
ConcurrencyThroughput/initial-drain-8     8.627m ± 17%   9.354m ± 11%       ~ (p=0.394 n=6)
geomean                                   133.6m         133.3m        -0.26%

                                        │ /tmp/old.txt │            /tmp/new.txt            │
                                        │     B/op     │     B/op      vs base              │
ConcurrencyThroughput/wal/batch=100-8     124.2Mi ± 0%   124.2Mi ± 0%       ~ (p=0.818 n=6)
ConcurrencyThroughput/wal/batch=1000-8    119.8Mi ± 0%   119.8Mi ± 0%       ~ (p=0.394 n=6)
ConcurrencyThroughput/wal/batch=10000-8   109.2Mi ± 0%   109.2Mi ± 0%       ~ (p=1.000 n=6)
ConcurrencyThroughput/initial-drain-8     13.49Mi ± 0%   13.49Mi ± 0%       ~ (p=0.370 n=6)
geomean                                   68.43Mi        68.43Mi       -0.00%

                                        │ /tmp/old.txt │           /tmp/new.txt            │
                                        │  allocs/op   │  allocs/op   vs base              │
ConcurrencyThroughput/wal/batch=100-8      780.5k ± 0%   780.5k ± 0%       ~ (p=0.937 n=6)
ConcurrencyThroughput/wal/batch=1000-8     313.3k ± 0%   313.3k ± 0%       ~ (p=0.093 n=6)
ConcurrencyThroughput/wal/batch=10000-8    97.75k ± 0%   97.75k ± 0%       ~ (p=0.844 n=6)
ConcurrencyThroughput/initial-drain-8      49.06k ± 0%   49.06k ± 0%       ~ (p=1.000 n=6)
geomean                                    185.0k        185.1k       +0.00%

                                        │ /tmp/old.txt │            /tmp/new.txt            │
                                        │  slots/sec   │  slots/sec    vs base              │
ConcurrencyThroughput/wal/batch=100-8     87.77k ±  1%   86.58k ±  2%       ~ (p=0.065 n=6)
ConcurrencyThroughput/wal/batch=1000-8    686.3k ±  2%   720.4k ±  2%  +4.97% (p=0.002 n=6)
ConcurrencyThroughput/wal/batch=10000-8   3.596M ±  8%   3.805M ±  3%  +5.81% (p=0.041 n=6)
ConcurrencyThroughput/initial-drain-8     23.18M ± 14%   21.40M ± 10%       ~ (p=0.394 n=6)
geomean                                   1.497M         1.501M        +0.28%

Compared against main (4acd7ee)

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a bug in the V1 in-memory concurrency index where CANCEL_IN_PROGRESS behaved like CANCEL_NEWEST due to using the default (oldest-first) comparator. The PR introduces a strategy-specific comparator selection so CANCEL_IN_PROGRESS ranks newer equal-priority slots ahead of older ones, and adds both Go and Python test coverage to prevent regressions—especially when SERVER_CONCURRENCY_IN_MEMORY_INDEX_ENABLED=true.

Changes:

  • Select a comparator based on concurrency strategy, using a newest-first tie-break for CANCEL_IN_PROGRESS.
  • Add Go unit/integration tests that pin the CANCEL_IN_PROGRESS recency behavior under the in-memory index.
  • Add Python task-level concurrency examples + tests and run them in CI with the in-memory index toggled on/off.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.

Show a summary per file
File Description
sdks/python/examples/worker.py Registers the new task-level concurrency example workflows so they can be exercised in the examples/test harness.
sdks/python/examples/concurrency_cancel_newest_task_level/worker.py Adds a task-level CANCEL_NEWEST example to exercise the in-memory index path.
sdks/python/examples/concurrency_cancel_newest_task_level/test_concurrency_cancel_newest_task_level.py Adds an async test asserting task-level CANCEL_NEWEST keeps the oldest run and cancels newer arrivals.
sdks/python/examples/concurrency_cancel_in_progress_task_level/worker.py Adds a task-level CANCEL_IN_PROGRESS example to exercise the in-memory index path.
sdks/python/examples/concurrency_cancel_in_progress_task_level/test_concurrency_cancel_in_progress_task_level.py Adds an async test asserting task-level CANCEL_IN_PROGRESS keeps the newest run and cancels older (including running) ones.
pkg/scheduling/v1/concurrency/strategy.go Switches from a fixed comparator to comparatorForStrategy, aligning heap ordering with strategy semantics.
pkg/scheduling/v1/concurrency/strategy_test.go Updates test strategy construction to use the same strategy-specific comparator selection.
pkg/scheduling/v1/concurrency/index.go Refines priorityCompare docs and introduces cancelInProgressCompare (newest-first tie-break) to match legacy semantics.
pkg/scheduling/v1/concurrency/cancel_in_progress_test.go Adds targeted unit tests to pin newest-wins behavior and preemption direction for equal-priority slots.
pkg/scheduling/v1/concurrency_integration_test.go Updates the in-memory CANCEL_IN_PROGRESS integration test description to reflect newest-first behavior and point to unit tests for ordering.
.github/workflows/sdk-python.yml Extends the SDK Python CI matrix to run with SERVER_CONCURRENCY_IN_MEMORY_INDEX_ENABLED both true/false and disambiguates uploaded artifact names.

## wait for the olap repo to catch up
await asyncio.sleep(5)

successful_run = hatchet.runs.get(to_run.workflow_run_id)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'll be less flaky to use await hatchet.runs.aio_get_details() instead - have been trying to do that everywhere (then don't need the sleep above this either)

await asyncio.sleep(5)

runs = sorted(
hatchet.runs.list(additional_metadata={"test_run_id": test_run_id}).rows,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
hatchet.runs.list(additional_metadata={"test_run_id": test_run_id}).rows,
await hatchet.runs.aio_list(additional_metadata={"test_run_id": test_run_id}).rows,

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Optional test failure: The load-deadlock job failed on this PR (optimistic-scheduling=true). This check is non-mandatory and does not block merging, but may be worth investigating. View logs

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Optional test failure: The load-deadlock job failed on this PR (optimistic-scheduling=false). This check is non-mandatory and does not block merging, but may be worth investigating. View logs

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Optional test failure: The load-deadlock job failed on this PR (optimistic-scheduling=true). This check is non-mandatory and does not block merging, but may be worth investigating. View logs

@abelanger5
abelanger5 merged commit a3b2075 into main Jul 16, 2026
75 of 76 checks passed
@abelanger5
abelanger5 deleted the belanger/concurrency-cancel-in-progress-fix branch July 16, 2026 18:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation engine Related to the core Hatchet engine github_actions Pull requests that update GitHub Actions code sdk-py Related to the Python sdk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants