Build powerful time-based automation workflows for your StateSet agents
npm install stateset-node @stateset/scheduler
import { StateSetClient } from 'stateset-node';
const client = new StateSetClient({
apiKey: process.env.STATESET_API_KEY
});
async function createDailyCheckIn() {
const schedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'daily_customer_check_in',
description: 'Check in with customers who have open issues',
schedule: {
type: 'cron',
expression: '0 9 * * 1-5', // 9 AM weekdays
timezone: 'America/New_York'
},
action: {
type: 'function',
function: 'check_open_issues',
parameters: {
priority: 'high',
age_days: 2
}
},
enabled: true,
metadata: {
category: 'customer_success',
owner: 'support_team'
}
});
console.log('Schedule created:', schedule.id);
return schedule;
}
async function createSmartFollowUp() {
const schedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'smart_purchase_follow_up',
description: 'Intelligent post-purchase follow-up based on order value and customer type',
// Complex scheduling rules
schedule: {
type: 'event_based',
trigger: 'order.completed',
delay: {
unit: 'hours',
value: 24,
business_hours_only: true
},
conditions: [
{
field: 'order.total',
operator: 'greater_than',
value: 100
},
{
field: 'customer.lifetime_value',
operator: 'greater_than',
value: 500
}
]
},
// Dynamic action based on context
action: {
type: 'workflow',
steps: [
{
type: 'evaluate',
condition: 'order.total > 1000',
true_action: {
type: 'send_message',
template: 'vip_thank_you',
channel: 'email'
},
false_action: {
type: 'send_message',
template: 'standard_thank_you',
channel: 'email'
}
},
{
type: 'wait',
duration: '7d'
},
{
type: 'send_message',
template: 'product_review_request',
channel: 'sms'
}
]
},
// Error handling
error_handling: {
retry_attempts: 3,
retry_delay: '5m',
on_failure: 'create_ticket'
}
});
return schedule;
}
// Common cron patterns
const cronPatterns = {
// Every hour
hourly: '0 * * * *',
// Every day at 9 AM
daily_morning: '0 9 * * *',
// Every Monday at 10 AM
weekly_monday: '0 10 * * 1',
// First day of month at midnight
monthly_start: '0 0 1 * *',
// Every 15 minutes during business hours
business_quarter_hour: '*/15 9-17 * * 1-5',
// Last Friday of month at 5 PM
monthly_last_friday: '0 17 * * 5L'
};
// Create schedule with cron
const cronSchedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'hourly_metrics_check',
schedule: {
type: 'cron',
expression: cronPatterns.hourly,
timezone: 'UTC'
},
action: {
type: 'function',
function: 'collect_hourly_metrics'
}
});
const intervalSchedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'continuous_monitoring',
schedule: {
type: 'interval',
every: {
unit: 'minutes',
value: 30
},
start_time: '2024-01-01T00:00:00Z',
end_time: '2024-12-31T23:59:59Z'
},
action: {
type: 'function',
function: 'monitor_system_health'
}
});
const eventSchedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'abandoned_cart_recovery',
schedule: {
type: 'event_based',
trigger: 'cart.abandoned',
delay: {
unit: 'hours',
value: 2
},
conditions: [
{
field: 'cart.value',
operator: 'greater_than',
value: 50
}
]
},
action: {
type: 'workflow',
workflow_id: 'abandoned_cart_recovery_flow'
}
});
const businessSchedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'quarterly_business_review',
schedule: {
type: 'business_calendar',
calendar: 'fiscal_2024',
events: [
'quarter_end',
'quarter_start'
],
offset: {
days: -5,
business_days_only: true
}
},
action: {
type: 'function',
function: 'prepare_quarterly_report'
},
notifications: {
on_start: ['email:manager@company.com'],
on_complete: ['slack:#reports']
}
});
async function createCustomerJourneySchedule() {
const journey = await client.schedules.create({
agent_id: 'agent_123',
name: 'new_customer_onboarding',
description: 'Automated 30-day onboarding journey',
schedule: {
type: 'journey',
trigger: 'customer.created',
steps: [
{
delay: '1h',
action: 'send_welcome_email'
},
{
delay: '1d',
action: 'check_first_login',
condition: 'customer.logins == 0',
true_action: 'send_login_reminder'
},
{
delay: '3d',
action: 'send_getting_started_guide'
},
{
delay: '7d',
action: 'schedule_onboarding_call',
condition: 'customer.plan == "enterprise"'
},
{
delay: '14d',
action: 'send_feature_highlights'
},
{
delay: '30d',
action: 'send_feedback_survey'
}
]
},
tracking: {
metrics: ['completion_rate', 'engagement_score'],
report_to: 'customer_success_dashboard'
}
});
return journey;
}
async function createEscalationSchedule() {
const escalation = await client.schedules.create({
agent_id: 'agent_123',
name: 'ticket_escalation_system',
schedule: {
type: 'continuous',
check_interval: '15m'
},
rules: [
{
name: 'urgent_escalation',
condition: {
all: [
{ field: 'ticket.priority', operator: 'equals', value: 'urgent' },
{ field: 'ticket.age_minutes', operator: 'greater_than', value: 30 },
{ field: 'ticket.status', operator: 'not_equals', value: 'resolved' }
]
},
action: {
type: 'escalate',
to: 'senior_support',
notification: 'immediate'
}
},
{
name: 'standard_escalation',
condition: {
all: [
{ field: 'ticket.priority', operator: 'equals', value: 'normal' },
{ field: 'ticket.age_hours', operator: 'greater_than', value: 4 }
]
},
action: {
type: 'escalate',
to: 'support_lead',
notification: 'email'
}
},
{
name: 'vip_escalation',
condition: {
all: [
{ field: 'customer.tier', operator: 'equals', value: 'vip' },
{ field: 'ticket.age_minutes', operator: 'greater_than', value: 15 }
]
},
action: {
type: 'escalate',
to: 'vip_support',
notification: 'phone'
}
}
]
});
return escalation;
}
class ScheduleMonitor {
async getScheduleMetrics(scheduleId, timeframe = '7d') {
const metrics = await client.schedules.getMetrics({
schedule_id: scheduleId,
timeframe: timeframe,
metrics: [
'execution_count',
'success_rate',
'average_duration',
'failure_reasons'
]
});
return {
health: this.calculateHealth(metrics),
performance: {
executions: metrics.execution_count,
success_rate: `${metrics.success_rate}%`,
avg_duration: `${metrics.average_duration}ms`,
reliability: this.calculateReliability(metrics)
},
issues: this.identifyIssues(metrics),
recommendations: this.generateRecommendations(metrics)
};
}
calculateHealth(metrics) {
if (metrics.success_rate >= 99) return 'excellent';
if (metrics.success_rate >= 95) return 'good';
if (metrics.success_rate >= 90) return 'fair';
return 'poor';
}
identifyIssues(metrics) {
const issues = [];
if (metrics.success_rate < 95) {
issues.push({
type: 'reliability',
severity: 'high',
message: `Success rate ${metrics.success_rate}% is below threshold`
});
}
if (metrics.average_duration > 5000) {
issues.push({
type: 'performance',
severity: 'medium',
message: 'Schedule execution taking longer than expected'
});
}
return issues;
}
}
// Pause all schedules for maintenance
async function pauseAllSchedules(reason) {
const schedules = await client.schedules.list({
filter: { enabled: true }
});
const results = await Promise.all(
schedules.map(schedule =>
client.schedules.update({
id: schedule.id,
enabled: false,
pause_reason: reason,
paused_at: new Date().toISOString()
})
)
);
console.log(`Paused ${results.length} schedules`);
return results;
}
// Migrate schedules to new timezone
async function migrateScheduleTimezones(fromTz, toTz) {
const schedules = await client.schedules.list({
filter: {
'schedule.timezone': fromTz,
'schedule.type': 'cron'
}
});
for (const schedule of schedules) {
const updatedCron = convertCronTimezone(
schedule.schedule.expression,
fromTz,
toTz
);
await client.schedules.update({
id: schedule.id,
schedule: {
...schedule.schedule,
expression: updatedCron,
timezone: toTz
}
});
}
}
class ScheduleTester {
async testSchedule(scheduleId, options = {}) {
const testRun = await client.schedules.test({
schedule_id: scheduleId,
mode: options.mode || 'dry_run',
test_data: options.testData || {},
simulate_time: options.simulateTime || new Date()
});
return {
would_execute: testRun.would_execute,
execution_time: testRun.execution_time,
action_preview: testRun.action_preview,
validation_errors: testRun.validation_errors,
estimated_duration: testRun.estimated_duration
};
}
async simulateScheduleRun(scheduleId, days = 7) {
const simulations = [];
const schedule = await client.schedules.get(scheduleId);
for (let i = 0; i < days * 24; i++) {
const simulatedTime = new Date();
simulatedTime.setHours(simulatedTime.getHours() + i);
const wouldRun = this.evaluateCron(
schedule.schedule.expression,
simulatedTime,
schedule.schedule.timezone
);
if (wouldRun) {
simulations.push({
time: simulatedTime,
action: schedule.action
});
}
}
return {
schedule_id: scheduleId,
simulation_period: `${days} days`,
expected_runs: simulations.length,
run_times: simulations
};
}
}
// Usage
const tester = new ScheduleTester();
const results = await tester.simulateScheduleRun('schedule_123', 30);
console.log(`Schedule would run ${results.expected_runs} times in 30 days`);
const resilientSchedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'critical_daily_task',
schedule: {
type: 'cron',
expression: '0 2 * * *' // 2 AM daily
},
action: {
type: 'function',
function: 'process_daily_reports'
},
error_handling: {
retry_strategy: {
max_attempts: 5,
delays: [30, 60, 300, 900, 1800], // seconds
backoff_type: 'exponential'
},
failure_actions: [
{
after_attempts: 3,
action: {
type: 'notify',
channel: 'email',
recipients: ['oncall@company.com'],
template: 'schedule_failure_warning'
}
},
{
after_attempts: 5,
action: {
type: 'escalate',
create_incident: true,
severity: 'high',
assign_to: 'oncall_engineer'
}
}
],
recovery: {
type: 'compensating_action',
action: 'run_backup_process',
notify_on_recovery: true
}
},
monitoring: {
alert_on_miss: true,
alert_on_delay: {
threshold_minutes: 15
},
health_check_endpoint: 'https://status.company.com/schedules/daily_task'
}
});
async function createDependentSchedules() {
// Parent schedule
const parentSchedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'data_collection',
schedule: { type: 'cron', expression: '0 1 * * *' },
action: { type: 'function', function: 'collect_daily_data' }
});
// Child schedule that depends on parent
const childSchedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'data_processing',
schedule: {
type: 'dependent',
depends_on: parentSchedule.id,
trigger: 'on_success',
delay: '30m'
},
action: { type: 'function', function: 'process_collected_data' }
});
// Grandchild schedule
const reportSchedule = await client.schedules.create({
agent_id: 'agent_123',
name: 'report_generation',
schedule: {
type: 'dependent',
depends_on: childSchedule.id,
trigger: 'on_complete',
conditions: [
{ field: 'output.record_count', operator: 'greater_than', value: 0 }
]
},
action: { type: 'function', function: 'generate_report' }
});
return { parentSchedule, childSchedule, reportSchedule };
}
// Good: Idempotent actions with proper error handling
const reliableSchedule = {
action: {
type: 'function',
function: 'process_orders',
parameters: {
mode: 'idempotent',
check_processed: true,
batch_size: 100
}
},
error_handling: {
retry_attempts: 3,
alert_on_failure: true
}
};
// Bad: Non-idempotent actions without safeguards
const unreliableSchedule = {
action: {
type: 'function',
function: 'send_emails',
parameters: {
send_all: true // Could send duplicates
}
}
};
// Good: Explicit timezone handling
const timezoneAwareSchedule = {
schedule: {
type: 'cron',
expression: '0 9 * * 1-5',
timezone: 'America/New_York',
observe_dst: true
},
metadata: {
business_hours: '9 AM - 5 PM EST/EDT',
skip_holidays: true
}
};
// Bad: Ambiguous timing
const ambiguousSchedule = {
schedule: {
type: 'cron',
expression: '0 9 * * *' // Which 9 AM?
}
};
class ScheduleOptimizer {
// Batch similar schedules
async optimizeSchedules() {
const schedules = await client.schedules.list();
// Group schedules by execution time
const grouped = this.groupByExecutionTime(schedules);
// Create batch processors
for (const [time, group] of Object.entries(grouped)) {
if (group.length > 5) {
await this.createBatchSchedule(time, group);
}
}
}
async createBatchSchedule(time, schedules) {
return client.schedules.create({
name: `batch_processor_${time}`,
schedule: { type: 'cron', expression: time },
action: {
type: 'batch',
actions: schedules.map(s => s.action),
parallel: true,
max_concurrent: 10
}
});
}
}
// Schedule debugger
async function debugSchedule(scheduleId) {
const debug = await client.schedules.debug({
schedule_id: scheduleId,
include: ['execution_history', 'next_runs', 'conflicts']
});
console.log('Schedule Debug Info:');
console.log('- Status:', debug.status);
console.log('- Last run:', debug.last_execution);
console.log('- Next 5 runs:', debug.next_runs.slice(0, 5));
console.log('- Conflicts:', debug.conflicts);
console.log('- Error rate:', debug.error_rate);
return debug;
}