diff --git a/.changeset/chilly-plums-pause.md b/.changeset/chilly-plums-pause.md new file mode 100644 index 00000000000..96eb4c317b1 --- /dev/null +++ b/.changeset/chilly-plums-pause.md @@ -0,0 +1,13 @@ +--- +"@trigger.dev/sdk": minor +"@trigger.dev/core": minor +--- + +Concurrency limits can now be paused and resumed, just like queues: `concurrencyLimits.pause(name)` stops every run holding the limit from being dequeued while keeping its configured bounds, and `concurrencyLimits.resume(name)` starts them again. + +```ts +import { concurrencyLimits } from "@trigger.dev/sdk"; + +await concurrencyLimits.pause("openai"); +await concurrencyLimits.resume("openai"); +``` diff --git a/.changeset/deprecate-queue-concurrency-mutations.md b/.changeset/deprecate-queue-concurrency-mutations.md new file mode 100644 index 00000000000..89ee740f832 --- /dev/null +++ b/.changeset/deprecate-queue-concurrency-mutations.md @@ -0,0 +1,5 @@ +--- +"@trigger.dev/sdk": patch +--- + +Deprecate `queues.overrideConcurrencyLimit` and `queues.resetConcurrencyLimit`. These operate on the legacy model where a queue carried its own concurrency limit; declare concurrency with the task `concurrency` option and manage it with `concurrencyLimits.override` and `concurrencyLimits.reset` instead. diff --git a/.server-changes/concurrency-allocation-hardening.md b/.server-changes/concurrency-allocation-hardening.md new file mode 100644 index 00000000000..9f08aed27b8 --- /dev/null +++ b/.server-changes/concurrency-allocation-hardening.md @@ -0,0 +1,6 @@ +--- +area: webapp +type: improvement +--- + +Allocating extra concurrency to environments now requires billing permissions, the same as purchasing it. Allocation changes are also applied atomically, so simultaneous edits can no longer exceed your purchased concurrency. diff --git a/.server-changes/session-transcript-inspector.md b/.server-changes/session-transcript-inspector.md new file mode 100644 index 00000000000..fe6dd1e49b5 --- /dev/null +++ b/.server-changes/session-transcript-inspector.md @@ -0,0 +1,5 @@ +--- +area: webapp +type: feature +--- +Download a session’s original saved transcript file from the session inspector. diff --git a/apps/webapp/app/components/queues/QueueControls.tsx b/apps/webapp/app/components/queues/QueueControls.tsx index 2995103c98c..5574da271a8 100644 --- a/apps/webapp/app/components/queues/QueueControls.tsx +++ b/apps/webapp/app/components/queues/QueueControls.tsx @@ -36,6 +36,7 @@ export function QueuePauseResumeButton({ iconOnly = false, withQueueName = false, disabled = false, + noun = "queue", }: { /** The "id" here is a friendlyId */ queue: { id: string; name: string; paused: boolean }; @@ -48,14 +49,21 @@ export function QueuePauseResumeButton({ /** Render the full "Pause/Resume {name} queue" label instead of the short "Pause"/"Resume". */ withQueueName?: boolean; disabled?: boolean; + /** What the row is called in every user-facing string: named concurrency limits pause through + * the same actions but their dialogs must say "limit". */ + noun?: "queue" | "limit"; }) { const [isOpen, setIsOpen] = useState(false); const label = queue.paused - ? `Resumes the "${queue.name}" queue so its runs can be dequeued again.` - : `Pauses all runs from being dequeued in the "${queue.name}" queue. Any executing runs will continue to run.`; + ? noun === "limit" + ? `Resumes the "${queue.name}" limit so runs holding it can be dequeued again.` + : `Resumes the "${queue.name}" queue so its runs can be dequeued again.` + : noun === "limit" + ? `Pauses all runs holding the "${queue.name}" limit from being dequeued. Any executing runs will continue to run.` + : `Pauses all runs from being dequeued in the "${queue.name}" queue. Any executing runs will continue to run.`; - const tooltip = disabled ? "You don't have permission to manage queues" : label; + const tooltip = disabled ? `You don't have permission to manage ${noun}s` : label; const trigger = showTooltip ? (