Repository navigation
Add shared thread-pool to HTTP API workflows runner - #1717
Merged
Merged
Conversation
PawelPeczek-Roboflow
requested review from
grzegorz-roboflow,
hansent,
probicheaux and
yeldarby
as code owners
November 14, 2025 12:39
yeldarby
approved these changes
Nov 14, 2025
hansent
reviewed
Nov 14, 2025
| os.getenv("HTTP_API_SHARED_WORKFLOWS_THREAD_POOL_ENABLED", "True") | ||
| ) | ||
| HTTP_API_SHARED_WORKFLOWS_THREAD_POOL_WORKERS = int( | ||
| os.getenv("HTTP_API_SHARED_WORKFLOWS_THREAD_POOL_WORKERS", "16") |
Collaborator
There was a problem hiding this comment.
seems reasonable. did we try differetn values? in past ive based default for this kind of thing on # of cpus available
Collaborator
Author
There was a problem hiding this comment.
no, purely gut-feeling-based default
davidnichols-ops
added a commit
to davidnichols-ops/inference
that referenced
this pull request
Sep 23, 2026
Build a single ThreadPoolExecutor per workflow run when the host passes no executor instead of one per DAG wave: create it lazily on the first wave that runs, dispatch each wave with a flat map (flat_dispatch) so scheduling matches the historical executor-less path, and shut it down in finally before stream-pipeline close so wave tasks drain in the same order the per-wave with-blocks did. Host-provided pools keep batched dispatch and are never built or shut by the engine, so the HTTP server and streaming pipeline are unchanged. Worker threads live for exactly one run. Framework context stays isolated per task through context snapshots and the unconditional rebinds in safe_execute_step; third-party threading.local set inside one step may be seen by later steps of the same run (the reuse profile hosted pools have had since roboflow#1717), and cannot cross runs because the threads are destroyed at run end. On a six-round counterbalanced benchmark, pool constructions fall from the wave count to one and median run latency drops from 1.10 to 0.71 ms on a 10-step chain (-35%) and from 5.08 to 3.01 ms on a 50-step chain (-41%), with single-wave, host-provided, and compute-heavy cells unchanged within noise. The 16 regression tests fail on unpatched base code with 10 failures (pool counts, dispatch shape, shutdown ordering, early- termination teardown) and pass here; suites report 6599 passed, 113 skipped (workflows package) and 1238 passed, 30 skipped (root server workflows).
davidnichols-ops
added a commit
to davidnichols-ops/inference
that referenced
this pull request
Sep 23, 2026
Build a single ThreadPoolExecutor per workflow run when the host passes no executor instead of one per DAG wave: create it lazily on the first wave that runs and dispatch each wave flat (flat_dispatch - submit the whole wave, collect results) so scheduling matches the historical executor-less path. A step error drains in-flight siblings before leaving run_steps_in_parallel, exactly where the per-wave with-blocks used to join, and the pool shuts down in a nested finally before stream-pipeline close so pipeline cleanup still runs if shutdown itself raises. Host-provided pools keep batched dispatch and are never built or shut by the engine, so the HTTP server and streaming pipeline are unchanged. Worker threads live for exactly one run. Framework context stays isolated per task through context snapshots and the unconditional rebinds in safe_execute_step; third-party threading.local set inside one step may be seen by later steps of the same run (the reuse profile hosted pools have had since roboflow#1717), and cannot cross runs because the threads are destroyed at run end. On a six-round counterbalanced benchmark, pool constructions fall from the wave count to one and median run latency drops from 1.10 to 0.71 ms on a 10-step chain (-35%) and from 5.08 to 3.01 ms on a 50-step chain (-41%), with single-wave, host-provided, and compute-heavy cells unchanged within noise. The 17 regression tests fail on unpatched base code with 11 failures (pool counts, dispatch shape, shutdown ordering, early-termination teardown) and pass here; suites report 6607 passed, 113 skipped (workflows package) and 1238 passed, 30 skipped (root server workflows).
davidnichols-ops
added a commit
to davidnichols-ops/inference
that referenced
this pull request
Sep 24, 2026
Build a single ThreadPoolExecutor per workflow run when the host passes no executor instead of one per DAG wave: create it lazily on the first wave that runs and dispatch each wave flat (flat_dispatch - submit the whole wave, collect results) so scheduling matches the historical executor-less path. A step error drains in-flight siblings before leaving run_steps_in_parallel, exactly where the per-wave with-blocks used to join, and the pool shuts down in a nested finally before stream-pipeline close so pipeline cleanup still runs if shutdown itself raises. Host-provided pools keep batched dispatch and are never built or shut by the engine, so the HTTP server and streaming pipeline are unchanged. Worker threads live for exactly one run. Framework context stays isolated per task through context snapshots and the unconditional rebinds in safe_execute_step; third-party threading.local set inside one step may be seen by later steps of the same run (the reuse profile hosted pools have had since roboflow#1717), and cannot cross runs because the threads are destroyed at run end. On a six-round counterbalanced benchmark, pool constructions fall from the wave count to one and median run latency drops from 1.10 to 0.71 ms on a 10-step chain (-35%) and from 5.08 to 3.01 ms on a 50-step chain (-41%), with single-wave, host-provided, and compute-heavy cells unchanged within noise. The 17 regression tests fail on unpatched base code with 11 failures (pool counts, dispatch shape, shutdown ordering, early-termination teardown) and pass here; suites report 6607 passed, 113 skipped (workflows package) and 1238 passed, 30 skipped (root server workflows).
PawelPeczek-Roboflow
added a commit
that referenced
this pull request
Sep 25, 2026
…uns (#3052) Build a single ThreadPoolExecutor per workflow run when the host passes no executor instead of one per DAG wave: create it lazily on the first wave that runs and dispatch each wave flat (flat_dispatch - submit the whole wave, collect results) so scheduling matches the historical executor-less path. A step error drains in-flight siblings before leaving run_steps_in_parallel, exactly where the per-wave with-blocks used to join, and the pool shuts down in a nested finally before stream-pipeline close so pipeline cleanup still runs if shutdown itself raises. Host-provided pools keep batched dispatch and are never built or shut by the engine, so the HTTP server and streaming pipeline are unchanged. Worker threads live for exactly one run. Framework context stays isolated per task through context snapshots and the unconditional rebinds in safe_execute_step; third-party threading.local set inside one step may be seen by later steps of the same run (the reuse profile hosted pools have had since #1717), and cannot cross runs because the threads are destroyed at run end. On a six-round counterbalanced benchmark, pool constructions fall from the wave count to one and median run latency drops from 1.10 to 0.71 ms on a 10-step chain (-35%) and from 5.08 to 3.01 ms on a 50-step chain (-41%), with single-wave, host-provided, and compute-heavy cells unchanged within noise. The 17 regression tests fail on unpatched base code with 11 failures (pool counts, dispatch shape, shutdown ordering, early-termination teardown) and pass here; suites report 6607 passed, 113 skipped (workflows package) and 1238 passed, 30 skipped (root server workflows). Co-authored-by: Paweł Pęczek <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adding shared thread-pool executor for workflows
Type of change
Please delete options that are not relevant.
How has this change been tested, please provide a testcase or example of how you tested the change?
Any specific deployment considerations
For example, documentation changes, usability, usage/costs, secrets, etc.
Docs