Skip to content

Scheduling

The scheduling service in Flows provides ways to execute code at specified times, either on a recurring schedule or after a specific delay. This enables blocks to perform time-based operations without requiring external triggers or manual intervention.

Timers can be linked with pending events for better observability of asynchronous operations.

Scheduling in Flows comes in two forms:

  1. Declarative scheduling - Predefined cron or frequency-based schedules specified in app or block definitions that run on a regular basis
  2. Imperative scheduling (timers) - Dynamically created one-time timers that trigger after a specified delay

These capabilities enable important patterns such as:

  • Polling external APIs for new data
  • Performing regular maintenance tasks like refreshing auth tokens
  • Implementing delays and timeouts
  • Retrying operations after failures
  • Checking the status of long-running processes

Declarative schedules are defined in the app or block schema and automatically managed by the Flows platform.

To add scheduled operations to an app or a block, include a schedules object in your block definition:

{
schedules: {
generateDailyReport: {
description: "Generates the daily summary report",
// Run at 8:00 AM every weekday
definition: {
type: "cron",
cron: {
expression: "0 8 * * 1-5",
location: "America/New_York",
},
},
onTrigger: async (input) => {
// Your report generation logic here...
},
},
},
},

Schedules can be marked as customizable, which allows them to be configured by users:

{
schedules: {
dataSync: {
description: "Synchronizes data from the external API",
customizable: true, // Users can customize this schedule
definition: {
type: "frequency",
frequency: {
interval: 1,
unit: "hours" // Default: every hour
}
},
onTrigger: async (input) => {
// Your data synchronization logic here...
},
},
},
}

When a schedule is marked as customizable:

  • The default schedule serves as the initial value
  • Users can modify the schedule through the block configuration UI
  • The schedule becomes part of the block’s configuration

In addition to declarative schedules, Flows provides an imperative API for setting one-time timers that trigger after a specified delay.

To create a timer, use the timers.app.set and timers.block.set functions:

import { timers } from "@slflows/sdk/v1";
// Set a timer to trigger after 30 seconds
const timerId = await timers.app.set(30, {
inputPayload: { message: "Don't forget to check the status!" },
description: "Reminder to check operation status",
});
console.log(`Timer set with ID: ${timerId}`);

The timer set functions take these arguments:

  • delaySeconds: How long to wait before triggering (in seconds)
  • options: Optional configuration object with:
    • inputPayload: Data to pass to the handler when the timer triggers
    • description: A human-readable description for the UI
    • pendingEventId: Optional pending event ID to associate with the timer
    • promptId: Optional prompt ID to associate with the timer

The function returns a unique ID for the timer, which can be used to unset it if needed.

To cancel a timer before it triggers, use the timers.app.unset and timers.block.unset functions:

import { timers } from "@slflows/sdk/v1";
// Cancel a previously set timer
await timers.block.unset(timerId);

To handle app or block timer events, implement the onTimer handler on the appropriate level:

{
onTimer: async (input) => {
const { timer } = input;
console.log("Timer triggered with payload:", timer.payload);
},
};

In addition to app and/or block contexts, onTimer handler receives a timer containing information about the timer that fired, including:

  • timer.payload: The payload data provided when the timer was set
  • timer.pendingEvent: Optional information about an associated pending event, containing:
    • id: The pending event ID
    • body: The current event body/payload (if any)
    • status: Current status description (if any)