Replies: 12 comments 31 replies
-
|
Another note: |
Beta Was this translation helpful? Give feedback.
-
|
Any thoughs on something like this? import { maxConcurrency } from "workflow"
async function maxConcurrentSteps() {
"use step";
maxConcurrency({ key: "freetier", limit: 20 }) // define limits here
// .. expensive thing
}With this, you can have also global configuration within the workflow config |
Beta Was this translation helpful? Give feedback.
-
|
I think @eersnington has a point, I thought the same on a first read Maybe: {
"use workflow"
await using lock("key", maxConcurrent: 30)
// continues when we get to acquire the lock, only 30 at a time
}This is possible to do now now with a simple hook (except for the using but it could help to make sure it releases) |
Beta Was this translation helpful? Give feedback.
-
|
You could also lean on default params as a discoverable place for “static” config and let the bundler pick that up instead of extra APIs. async function myWorkflow(...args, options = { maxConcurrency: 10 }) {
"use workflow";
}
async function myStep(...args, options = { maxConcurrency: 5 }) {
"use step";
}The idea: Feels like a light-weight middle ground between .maxConcurrency properties and an in-body setDefaults() call. |
Beta Was this translation helpful? Give feedback.
-
|
What is the default concurrency key? Does it include the deployment ID or is it purely derived from the function and file name? |
Beta Was this translation helpful? Give feedback.
-
|
I agree with @eersnington on it being contained within the function itself. However I like @pranaygp's proposed import { setDefaults } from "workflow"
async function step() {
"use step";
setDefaults({ maxConcurrency: 5, maxRetries: 1 })
// ..
}Im assuming more default options are not too far down the road |
Beta Was this translation helpful? Give feedback.
-
|
Can these defaults be changed on the fly? Does this scenario play out properly in your head? import { setDefaults } from "workflow"
import { customerAConcurrency } from "../customer-configs"
async function parentWorkflow() {
"use workflow";
setDefaults({ maxConcurrency: customerAConcurrency })
// ...
}Assuming yes; if the customerAConcurrency goes from 100 to 50 while there are 100 currently running, what is the expected behavior for the extra 50 workflows already running in that queue? |
Beta Was this translation helpful? Give feedback.
-
|
One other thing I'm curious about, is if there would be a way to move the priority of a specific step. So if we have global workflow limits that are currently in place, and the queue is growing, but theres one particular job for one particular key that I want to expedite, could there be a mechanism to do that. |
Beta Was this translation helpful? Give feedback.
-
|
is there also a general max number of total steps that can be executed as a general infra constraint? |
Beta Was this translation helpful? Give feedback.
-
|
What use case is there for max retries infinite? Seems like a good way to
get a runaway bill unexpectedly
…On Tue, Nov 11, 2025, 8:10 p.m. Pranay Prakash ***@***.***> wrote:
yup. It's not in this RFC yet but priority queueing does seem pretty
important - #301 (reply in thread)
<#301 (reply in thread)>
—
Reply to this email directly, view it on GitHub
<#301 (reply in thread)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAZYLDTLYW6FF542VPTDKSD34KCHTAVCNFSM6AAAAACLXOAOE2VHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTIOJUGE2DAMY>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
|
been thinking about this point -> how would maxConcurrency interact with long running or suspended workflows (sleep("time") api)? |
Beta Was this translation helpful? Give feedback.
-
|
would this become a recommended way to have “unique jobs” (one per organization, one per slack channel, etc)? Instead of a singleton workflow + infinite loop + hook resume, you can use a concurrency of 1 and fire a new workflow? One of the things I’ve been trying to figure out with infinite workflows + hooks is figuring out when/where to start() them so you know they’re always running by the time you resume them. |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Concurrency
Updated RFC
In light of a comment from @ale-vigano below, we decided to completely redo the concurrency spec. The idea is extremely simple now.
workflowwill simply expose a nativelockprimitive that acts as a distributed semaphore and is meant to be used inside "workflow" functions.Similar to
hookandsleep,lockwill consume a a concurrency slot on a queue while it is "in scope", and if no concurrency slots are available, it will suspend the workflow, and resume when there is one.It turns out that we can model the various variations of multi tenancy queuing, prority queueing, etc. as syntactic sugar on top of the lock primitive, and the lock primitive is a lot more powerful and extensible as a primitive.
We'll fill out the details here soon with examples and the exact API spec, and how it works with the world spec to be compatible with any queue, etc.
Initial draft for posteritry
Note:
useStepis a placeholder name. It's not a replacement for"use step"which still needs to be used to properly demarcate step functions to the bundler. It's just a function that lets you augment the declared behavior of a step at invoke time. For instance, it could even be used to augment the defaultmaxRetries. Open to naming suggestions :)Beta Was this translation helpful? Give feedback.
All reactions