Context
A DevForge MCP audit (PRP 003, release v2.5.1) confirmed that the optimize_images handler exposes a parallelism: int input that is currently a no-op — neither the Go handler nor the OptimizeJob protocol does anything with it.
The decision
There are two reasonable homes for parallelism, and they have different tradeoffs:
Option A — dpf-side flag
Add parallelism: u32 (or Option<u32>) to OptimizeJob. dpf processes the inputs slice using a Rayon (or Tokio) worker pool sized by the flag.
Pros: single subprocess invocation, dpf controls CPU affinity, scales to whatever the runtime can handle. Survives the new DevForge dpf.Pool (introduced in DevForge v2.5.1, which serializes one job at a time per StreamClient).
Cons: requires Rust-side concurrency model; complexity around backpressure, panic isolation, error aggregation.
Option B — handler-side goroutines
The DevForge handler splits inputs into N groups and fires N independent OptimizeJob calls in parallel via the dpf.Pool (which is already pool-backed since v2.5.1).
Pros: zero dpf changes. Reuses the pool architecture DevForge already built (DEVFORGE_DPF_POOL_SIZE env var).
Cons: bounded by the DevForge pool size (default 2). Each subprocess pays its own startup cost. Cross-job coordination (e.g. shared dictionaries) is harder.
What DevForge needs to know
Whatever the call, DevForge will mirror it. If Option A, the handler passes input.Parallelism through. If Option B, the handler shards Inputs and fans out via the pool, ignoring Parallelism or reinterpreting it as ''how many concurrent jobs to dispatch''.
References
- DevForge commits:
3d1884b (introduces dpf.Pool), 5235038
- DevForge release: v2.5.1
- DevForge memory:
prp/003-tools-efficiency-and-reuse/preexisting-bugs
Context
A DevForge MCP audit (PRP 003, release v2.5.1) confirmed that the
optimize_imageshandler exposes aparallelism: intinput that is currently a no-op — neither the Go handler nor theOptimizeJobprotocol does anything with it.The decision
There are two reasonable homes for parallelism, and they have different tradeoffs:
Option A — dpf-side flag
Add
parallelism: u32(orOption<u32>) toOptimizeJob. dpf processes theinputsslice using a Rayon (or Tokio) worker pool sized by the flag.Pros: single subprocess invocation, dpf controls CPU affinity, scales to whatever the runtime can handle. Survives the new DevForge
dpf.Pool(introduced in DevForge v2.5.1, which serializes one job at a time perStreamClient).Cons: requires Rust-side concurrency model; complexity around backpressure, panic isolation, error aggregation.
Option B — handler-side goroutines
The DevForge handler splits
inputsinto N groups and fires N independentOptimizeJobcalls in parallel via thedpf.Pool(which is already pool-backed since v2.5.1).Pros: zero dpf changes. Reuses the pool architecture DevForge already built (
DEVFORGE_DPF_POOL_SIZEenv var).Cons: bounded by the DevForge pool size (default 2). Each subprocess pays its own startup cost. Cross-job coordination (e.g. shared dictionaries) is harder.
What DevForge needs to know
Whatever the call, DevForge will mirror it. If Option A, the handler passes
input.Parallelismthrough. If Option B, the handler shardsInputsand fans out via the pool, ignoringParallelismor reinterpreting it as ''how many concurrent jobs to dispatch''.References
3d1884b(introducesdpf.Pool),5235038prp/003-tools-efficiency-and-reuse/preexisting-bugs