Documentation Index Fetch the complete documentation index at: https://mintlify.com/rjdellecese/confect/llms.txt
Use this file to discover all available pages before exploring further.
The Scheduler service allows you to schedule mutations to run at a specific time or after a delay. This is essential for implementing delayed tasks, reminders, background jobs, and time-based workflows.
Overview
Schedule After Delay Run a function after a specific duration
Schedule at Time Run a function at an exact timestamp
Effect Integration Use Effect’s Duration and DateTime types
Cancellable Cancel scheduled functions before they run
Accessing the Scheduler
The Scheduler service is available in mutations and actions:
import { Scheduler } from "@confect/server" ;
import { Effect , Duration } from "effect" ;
const scheduleTask = Effect . gen ( function* () {
const scheduler = yield * Scheduler ;
// Schedule a function
yield * scheduler . runAfter (
Duration . hours ( 1 ),
refs . internal . tasks . process ,
{ taskId: "task-123" }
);
});
Scheduling Methods
runAfter
Schedule a function to run after a duration:
import { Scheduler } from "@confect/server" ;
import { Effect , Duration } from "effect" ;
import { refs } from "../confect/_generated/refs" ;
const scheduleAfterDelay = Effect . gen ( function* () {
const scheduler = yield * Scheduler ;
// Schedule after 5 minutes
yield * scheduler . runAfter (
Duration . minutes ( 5 ),
refs . internal . notifications . send ,
{ userId: "user-123" , message: "Reminder" }
);
// Schedule after 1 hour
yield * scheduler . runAfter (
Duration . hours ( 1 ),
refs . internal . cleanup . removeOldData ,
{}
);
// Schedule after 30 seconds
yield * scheduler . runAfter (
Duration . seconds ( 30 ),
refs . internal . processing . retry ,
{ attemptId: "attempt-456" }
);
});
Use Effect’s Duration API to create type-safe durations: Duration.seconds(), Duration.minutes(), Duration.hours(), Duration.days()
runAt
Schedule a function to run at a specific time:
import { Scheduler } from "@confect/server" ;
import { Effect , DateTime } from "effect" ;
import { refs } from "../confect/_generated/refs" ;
const scheduleAtTime = Effect . gen ( function* () {
const scheduler = yield * Scheduler ;
// Schedule at specific timestamp
const targetTime = DateTime . unsafeMake ( new Date ( "2026-03-08T12:00:00Z" ));
yield * scheduler . runAt (
targetTime ,
refs . internal . reports . generate ,
{ reportType: "monthly" }
);
});
Use Effect’s DateTime API for type-safe date/time handling.
Common Use Cases
Email Verification Reminder
import { FunctionImpl , DatabaseWriter , Scheduler } from "@confect/server" ;
import { Effect , Duration } from "effect" ;
const registerUser = FunctionImpl . make (
api ,
"users" ,
"register" ,
({ email , password }) =>
Effect . gen ( function* () {
const db = yield * DatabaseWriter < typeof databaseSchema >();
const scheduler = yield * Scheduler ;
// Create user
const userId = yield * db . table ( "users" ). insert ({
email ,
passwordHash: password , // hash this!
verified: false ,
createdAt: Date . now (),
});
// Send verification email immediately
// (implement this)
// Schedule reminder after 24 hours
yield * scheduler . runAfter (
Duration . hours ( 24 ),
refs . internal . users . sendVerificationReminder ,
{ userId }
);
return { userId };
}). pipe ( Effect . orDie )
);
Trial Expiration
const startTrial = FunctionImpl . make (
api ,
"subscriptions" ,
"startTrial" ,
({ userId }) =>
Effect . gen ( function* () {
const db = yield * DatabaseWriter < typeof databaseSchema >();
const scheduler = yield * Scheduler ;
// Create subscription
const subscriptionId = yield * db . table ( "subscriptions" ). insert ({
userId ,
status: "trial" ,
startedAt: Date . now (),
});
// Schedule trial end after 14 days
yield * scheduler . runAfter (
Duration . days ( 14 ),
refs . internal . subscriptions . endTrial ,
{ subscriptionId }
);
return { subscriptionId };
}). pipe ( Effect . orDie )
);
Retry with Exponential Backoff
const retryWithBackoff = (
attempt : number ,
maxAttempts : number ,
taskId : string
) =>
Effect . gen ( function* () {
const scheduler = yield * Scheduler ;
if ( attempt >= maxAttempts ) {
return yield * Effect . fail ( new Error ( "Max retries reached" ));
}
// Calculate exponential backoff: 2^attempt minutes
const delayMinutes = Math . pow ( 2 , attempt );
yield * scheduler . runAfter (
Duration . minutes ( delayMinutes ),
refs . internal . tasks . retry ,
{ taskId , attempt: attempt + 1 }
);
});
Session Cleanup
const createSession = FunctionImpl . make (
api ,
"sessions" ,
"create" ,
({ userId , expiresInHours = 24 }) =>
Effect . gen ( function* () {
const db = yield * DatabaseWriter < typeof databaseSchema >();
const scheduler = yield * Scheduler ;
const sessionId = yield * db . table ( "sessions" ). insert ({
userId ,
token: generateToken (),
createdAt: Date . now (),
});
// Schedule cleanup when session expires
yield * scheduler . runAfter (
Duration . hours ( expiresInHours ),
refs . internal . sessions . cleanup ,
{ sessionId }
);
return { sessionId };
}). pipe ( Effect . orDie )
);
Scheduled Function Implementation
Implement the scheduled functions as internal mutations:
const sendVerificationReminder = FunctionImpl . make (
api ,
"users" ,
"sendVerificationReminder" ,
({ userId }) =>
Effect . gen ( function* () {
const db = yield * DatabaseReader < typeof databaseSchema >();
const user = yield * db . table ( "users" ). get ( userId );
// Only send if still not verified
if ( ! user . verified ) {
// Send reminder email
yield * sendEmail ( user . email , "Please verify your email" );
}
}). pipe ( Effect . orDie )
);
const endTrial = FunctionImpl . make (
api ,
"subscriptions" ,
"endTrial" ,
({ subscriptionId }) =>
Effect . gen ( function* () {
const db = yield * DatabaseWriter < typeof databaseSchema >();
yield * db . table ( "subscriptions" ). patch ( subscriptionId , {
status: "expired" ,
endedAt: Date . now (),
});
}). pipe ( Effect . orDie )
);
Scheduled functions must be internal mutations or actions. They cannot be public functions.
Canceling Scheduled Functions
You can cancel scheduled functions before they run:
import { DatabaseWriter } from "@confect/server" ;
import { Effect } from "effect" ;
const verifyEmail = FunctionImpl . make (
api ,
"users" ,
"verify" ,
({ userId , token }) =>
Effect . gen ( function* () {
const db = yield * DatabaseWriter < typeof databaseSchema >();
// Verify the user
yield * db . table ( "users" ). patch ( userId , {
verified: true ,
});
// Find and cancel the reminder
const scheduled = yield * db
. table ( "_scheduled_functions" )
. filter (( q ) =>
q . and (
q . eq ( q . field ( "name" ), "internal/users/sendVerificationReminder" ),
q . eq ( q . field ( "state.kind" ), "pending" )
)
)
. first ();
if ( scheduled ) {
yield * db . table ( "_scheduled_functions" ). delete ( scheduled . _id );
}
}). pipe ( Effect . orDie )
);
Querying Scheduled Functions
View scheduled functions in the _scheduled_functions system table:
const listScheduledTasks = Effect . gen ( function* () {
const db = yield * DatabaseReader < typeof databaseSchema >();
const scheduled = yield * db
. table ( "_scheduled_functions" )
. filter (( q ) => q . eq ( q . field ( "state.kind" ), "pending" ))
. collect ();
return scheduled . map (( task ) => ({
id: task . _id ,
name: task . name ,
scheduledTime: task . scheduledTime ,
args: task . args ,
}));
});
The _scheduled_functions table tracks all scheduled functions with their state: pending, inProgress, success, failed, or canceled.
Scheduling from Actions
You can also schedule functions from actions:
import { Scheduler , MutationRunner } from "@confect/server" ;
import { Effect , Duration } from "effect" ;
const processWebhook = FunctionImpl . make (
api ,
"webhooks" ,
"process" ,
({ payload }) =>
Effect . gen ( function* () {
const scheduler = yield * Scheduler ;
const runMutation = yield * MutationRunner ;
// Validate webhook
const valid = validateWebhook ( payload );
if ( ! valid ) {
return yield * Effect . fail ( new Error ( "Invalid webhook" ));
}
// Store webhook data
const webhookId = yield * runMutation (
refs . internal . webhooks . store ,
{ payload }
);
// Schedule processing
yield * scheduler . runAfter (
Duration . seconds ( 30 ),
refs . internal . webhooks . processDelayed ,
{ webhookId }
);
}). pipe ( Effect . orDie )
);
Scheduled Function Arguments
Scheduled functions receive the arguments you pass:
// Scheduling
yield * scheduler . runAfter (
Duration . hours ( 1 ),
refs . internal . tasks . process ,
{
taskId: "task-123" ,
priority: "high" ,
metadata: { source: "api" },
}
);
// Implementation
const processTask = FunctionImpl . make (
api ,
"tasks" ,
"process" ,
({ taskId , priority , metadata }) =>
Effect . gen ( function* () {
// taskId, priority, and metadata are available
console . log ( `Processing task ${ taskId } with priority ${ priority } ` );
// Process task...
}). pipe ( Effect . orDie )
);
Time Zone Considerations
import { DateTime } from "effect" ;
const scheduleDailyReport = Effect . gen ( function* () {
const scheduler = yield * Scheduler ;
// Schedule for 9 AM tomorrow in user's timezone
const now = DateTime . now ();
const tomorrow = DateTime . add ( now , Duration . days ( 1 ));
const targetTime = DateTime . setHours ( tomorrow , 9 , 0 , 0 , 0 );
yield * scheduler . runAt (
targetTime ,
refs . internal . reports . generateDaily ,
{ userId: "user-123" }
);
});
Effect’s DateTime API uses UTC by default. Convert to specific time zones using DateTime utilities.
Best Practices
Use Internal Functions
Always schedule internal mutations or actions, never public functions.
Handle Failures
Implement error handling in scheduled functions - they may fail and won’t automatically retry.
Store Schedule IDs
If you need to cancel scheduled functions, store their IDs in your database.
Idempotent Operations
Make scheduled functions idempotent in case they run multiple times.
Scheduled functions have a maximum execution time of 10 minutes (same as regular mutations). Break long-running tasks into smaller chunks.
Limitations
Scheduled functions must be mutations or actions (not queries)
Minimum scheduling delay is 1 second
Maximum scheduling delay is 5 years
Functions are scheduled in UTC time
Next Steps
Crons Schedule recurring tasks
Functions Learn about mutations and actions
Database Store scheduling metadata
Node Actions Schedule Node.js actions