Skip to content

Commit 6891a22

Browse files
refactor(wait): rename Suspend Workflow toggle to Async
1 parent 36f5dfd commit 6891a22

3 files changed

Lines changed: 41 additions & 43 deletions

File tree

apps/sim/blocks/blocks/wait.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ export const WaitBlock: BlockConfig = {
1010
name: 'Wait',
1111
description: 'Pause workflow execution for a time interval',
1212
longDescription:
13-
'Pauses workflow execution for a specified time interval. By default the wait runs in-process for up to 5 minutes. Enable Suspend Workflow to pause the run on disk and resume automatically for waits up to 30 days.',
13+
'Pauses workflow execution for a specified time interval. By default the wait runs in-process for up to 5 minutes. Enable Async to pause the run on disk and resume automatically for waits up to 30 days.',
1414
bestPractices: `
1515
- Configure the wait amount and unit
1616
- Default mode runs in-process and caps at 5 minutes
17-
- Enable Suspend Workflow for longer waits (up to 30 days); seconds are not available in this mode
17+
- Enable Async for longer waits (up to 30 days); seconds are not available in this mode
1818
- Enter a positive number for the wait amount
1919
`,
2020
category: 'blocks',
@@ -26,7 +26,7 @@ export const WaitBlock: BlockConfig = {
2626
id: 'timeValue',
2727
title: 'Wait Amount',
2828
type: 'short-input',
29-
description: 'Max 5 minutes (300 seconds). Enable Suspend Workflow for up to 30 days.',
29+
description: 'Max 5 minutes (300 seconds). Enable Async for up to 30 days.',
3030
placeholder: '10',
3131
value: () => '10',
3232
required: true,
@@ -41,7 +41,7 @@ export const WaitBlock: BlockConfig = {
4141
],
4242
value: () => 'seconds',
4343
required: true,
44-
condition: { field: 'suspend', value: true, not: true },
44+
condition: { field: 'async', value: true, not: true },
4545
},
4646
{
4747
id: 'timeUnitLong',
@@ -54,35 +54,35 @@ export const WaitBlock: BlockConfig = {
5454
],
5555
value: () => 'minutes',
5656
required: true,
57-
condition: { field: 'suspend', value: true },
57+
condition: { field: 'async', value: true },
5858
},
5959
{
60-
id: 'suspend',
61-
title: 'Suspend Workflow',
60+
id: 'async',
61+
title: 'Async',
6262
type: 'switch',
6363
tooltip:
64-
'By default, the workflow pauses in memory and can wait up to 5 minutes. Turn this on to suspend the run to disk so it can wait much longer (up to 30 days) — execution resumes automatically when the timer fires. Seconds aren’t available while suspended.',
64+
'By default, the workflow pauses in memory and can wait up to 5 minutes. Turn this on to run asynchronously — the workflow is saved to disk and resumed automatically when the timer fires, allowing waits up to 30 days. Seconds aren’t available in async mode.',
6565
},
6666
],
6767
tools: {
6868
access: [],
6969
},
7070
inputs: {
71-
suspend: {
71+
async: {
7272
type: 'boolean',
73-
description: 'Suspend the workflow to allow waits up to 30 days',
73+
description: 'Run the wait asynchronously to allow durations up to 30 days',
7474
},
7575
timeValue: {
7676
type: 'string',
7777
description: 'Wait duration value',
7878
},
7979
timeUnit: {
8080
type: 'string',
81-
description: 'Wait duration unit when suspend is off (seconds or minutes)',
81+
description: 'Wait duration unit when async is off (seconds or minutes)',
8282
},
8383
timeUnitLong: {
8484
type: 'string',
85-
description: 'Wait duration unit when suspend is on (minutes, hours, or days)',
85+
description: 'Wait duration unit when async is on (minutes, hours, or days)',
8686
},
8787
},
8888
outputs: {

apps/sim/executor/handlers/wait/wait-handler.test.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -120,27 +120,27 @@ describe('WaitBlockHandler', () => {
120120
).rejects.toThrow('Unknown wait unit: fortnights')
121121
})
122122

123-
it('should reject suspending waits longer than the 30-day ceiling', async () => {
123+
it('should reject async waits longer than the 30-day ceiling', async () => {
124124
await expect(
125125
handler.execute(mockContext, mockBlock, {
126-
suspend: true,
126+
async: true,
127127
timeValue: '31',
128128
timeUnitLong: 'days',
129129
})
130130
).rejects.toThrow('Wait time exceeds maximum of 30 days')
131131
})
132132

133-
it('should reject non-suspending waits longer than 5 minutes', async () => {
133+
it('should reject synchronous waits longer than 5 minutes', async () => {
134134
await expect(
135135
handler.execute(mockContext, mockBlock, { timeValue: '10', timeUnit: 'minutes' })
136136
).rejects.toThrow('Wait time exceeds maximum of 5 minutes')
137137
})
138138

139-
it('should default the suspend unit to minutes when timeUnitLong is missing', async () => {
139+
it('should default the async unit to minutes when timeUnitLong is missing', async () => {
140140
vi.setSystemTime(new Date('2026-04-28T00:00:00.000Z'))
141141

142142
const result = (await handler.execute(mockContext, mockBlock, {
143-
suspend: true,
143+
async: true,
144144
timeValue: '3',
145145
})) as Record<string, any>
146146

@@ -149,14 +149,14 @@ describe('WaitBlockHandler', () => {
149149
expect(result.status).toBe('waiting')
150150
})
151151

152-
it('should reject seconds as a unit when Suspend Workflow is enabled', async () => {
152+
it('should reject seconds as a unit when Async is enabled', async () => {
153153
await expect(
154154
handler.execute(mockContext, mockBlock, {
155-
suspend: true,
155+
async: true,
156156
timeValue: '30',
157157
timeUnitLong: 'seconds',
158158
})
159-
).rejects.toThrow('Seconds are not allowed when Suspend Workflow is enabled')
159+
).rejects.toThrow('Seconds are not allowed when Async is enabled')
160160
})
161161

162162
it('should still execute in-process at the 5-minute boundary', async () => {
@@ -177,7 +177,7 @@ describe('WaitBlockHandler', () => {
177177
it('should suspend the workflow when wait exceeds the in-process threshold', async () => {
178178
vi.setSystemTime(new Date('2026-04-28T00:00:00.000Z'))
179179

180-
const inputs = { suspend: true, timeValue: '10', timeUnitLong: 'minutes' }
180+
const inputs = { async: true, timeValue: '10', timeUnitLong: 'minutes' }
181181

182182
const result = (await handler.execute(mockContext, mockBlock, inputs)) as Record<string, any>
183183

@@ -200,7 +200,7 @@ describe('WaitBlockHandler', () => {
200200
it('should suspend the workflow for multi-day waits', async () => {
201201
vi.setSystemTime(new Date('2026-04-28T00:00:00.000Z'))
202202

203-
const inputs = { suspend: true, timeValue: '2', timeUnitLong: 'days' }
203+
const inputs = { async: true, timeValue: '2', timeUnitLong: 'days' }
204204

205205
const result = (await handler.execute(mockContext, mockBlock, inputs)) as Record<string, any>
206206

@@ -218,7 +218,7 @@ describe('WaitBlockHandler', () => {
218218
vi.setSystemTime(new Date('2026-04-28T00:00:00.000Z'))
219219

220220
const result = (await handler.execute(mockContext, mockBlock, {
221-
suspend: true,
221+
async: true,
222222
timeValue: '3',
223223
timeUnitLong: 'hours',
224224
})) as Record<string, any>
@@ -271,7 +271,7 @@ describe('WaitBlockHandler', () => {
271271
mockContext.abortSignal = abortController.signal
272272

273273
const result = (await handler.execute(mockContext, mockBlock, {
274-
suspend: true,
274+
async: true,
275275
timeValue: '1',
276276
timeUnitLong: 'hours',
277277
})) as Record<string, any>
@@ -299,7 +299,7 @@ describe('WaitBlockHandler', () => {
299299
vi.setSystemTime(new Date('2026-04-28T00:00:00.000Z'))
300300

301301
const result = (await handler.execute(mockContext, mockBlock, {
302-
suspend: true,
302+
async: true,
303303
timeValue: '1.5',
304304
timeUnitLong: 'days',
305305
})) as Record<string, any>
@@ -310,11 +310,11 @@ describe('WaitBlockHandler', () => {
310310
expect(result._pauseMetadata.pauseKind).toBe('time')
311311
})
312312

313-
it('should always suspend when suspend is enabled, even for short waits', async () => {
313+
it('should always suspend when async is enabled, even for short waits', async () => {
314314
vi.setSystemTime(new Date('2026-04-28T00:00:00.000Z'))
315315

316316
const result = (await handler.execute(mockContext, mockBlock, {
317-
suspend: true,
317+
async: true,
318318
timeValue: '2',
319319
timeUnitLong: 'minutes',
320320
})) as Record<string, any>

apps/sim/executor/handlers/wait/wait-handler.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import type { SerializedBlock } from '@/serializer/types'
1010

1111
const CANCELLATION_CHECK_INTERVAL_MS = 500
1212

13-
/** Hard ceiling for in-process (non-suspending) waits. */
13+
/** Hard ceiling for in-process (synchronous) waits. */
1414
const MAX_INPROCESS_WAIT_MS = 5 * 60 * 1000
1515

16-
/** Hard ceiling for suspending waits. */
17-
const MAX_SUSPEND_WAIT_MS = 30 * 24 * 60 * 60 * 1000
16+
/** Hard ceiling for async waits. */
17+
const MAX_ASYNC_WAIT_MS = 30 * 24 * 60 * 60 * 1000
1818

1919
interface SleepOptions {
2020
signal?: AbortSignal
@@ -91,10 +91,10 @@ function isWaitUnit(value: string): value is WaitUnit {
9191
/**
9292
* Handler for Wait blocks that pause workflow execution for a time delay.
9393
*
94-
* Default (suspend=false) waits are held in-process via an interruptible sleep and capped at 5 minutes.
95-
* When suspend=true is set, the workflow is always suspended by returning {@link PauseMetadata} with
94+
* Default (async=false) waits are held in-process via an interruptible sleep and capped at 5 minutes.
95+
* When async=true is set, the workflow is always suspended by returning {@link PauseMetadata} with
9696
* `pauseKind: 'time'`; the cron-driven resume poller (see `/api/resume/poll`) picks the execution back
97-
* up once `resumeAt` is reached. Suspend caps at 30 days.
97+
* up once `resumeAt` is reached. Async caps at 30 days.
9898
*/
9999
export class WaitBlockHandler implements BlockHandler {
100100
canHandle(block: SerializedBlock): boolean {
@@ -124,9 +124,9 @@ export class WaitBlockHandler implements BlockHandler {
124124
executionOrder?: number
125125
}
126126
): Promise<BlockOutput> {
127-
const suspend = inputs.suspend === true || inputs.suspend === 'true'
127+
const isAsync = inputs.async === true || inputs.async === 'true'
128128
const timeValue = Number.parseFloat(inputs.timeValue || '10')
129-
const timeUnit = suspend ? inputs.timeUnitLong || 'minutes' : inputs.timeUnit || 'seconds'
129+
const timeUnit = isAsync ? inputs.timeUnitLong || 'minutes' : inputs.timeUnit || 'seconds'
130130

131131
if (!Number.isFinite(timeValue) || timeValue <= 0) {
132132
throw new Error('Wait amount must be a positive number')
@@ -136,23 +136,21 @@ export class WaitBlockHandler implements BlockHandler {
136136
throw new Error(`Unknown wait unit: ${timeUnit}`)
137137
}
138138

139-
if (suspend && timeUnit === 'seconds') {
140-
throw new Error('Seconds are not allowed when Suspend Workflow is enabled')
139+
if (isAsync && timeUnit === 'seconds') {
140+
throw new Error('Seconds are not allowed when Async is enabled')
141141
}
142142

143143
const waitMs = Math.round(timeValue * UNIT_TO_MS[timeUnit])
144144

145-
if (suspend) {
146-
if (waitMs > MAX_SUSPEND_WAIT_MS) {
145+
if (isAsync) {
146+
if (waitMs > MAX_ASYNC_WAIT_MS) {
147147
throw new Error('Wait time exceeds maximum of 30 days')
148148
}
149149
} else if (waitMs > MAX_INPROCESS_WAIT_MS) {
150-
throw new Error(
151-
'Wait time exceeds maximum of 5 minutes; enable Suspend Workflow to wait up to 30 days'
152-
)
150+
throw new Error('Wait time exceeds maximum of 5 minutes; enable Async to wait up to 30 days')
153151
}
154152

155-
if (!suspend) {
153+
if (!isAsync) {
156154
const completed = await sleep(waitMs, {
157155
signal: ctx.abortSignal,
158156
executionId: ctx.executionId,

0 commit comments

Comments
 (0)