Skip to content
Closed
71 changes: 71 additions & 0 deletions workers/main/src/configs/schedules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Client } from '@temporalio/client';

import { logger } from '../index';
import { weeklyFinancialReportsWorkflow } from '../workflows';
import { workerConfig } from './worker';

const SCHEDULE_ID = 'weekly-financial-report-schedule';
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

/**
* Sets up the weekly financial report schedule
* Schedule runs every Tuesday at 1 PM America/New_York time (EST/EDT)
* @param client - Temporal client instance
*/
export async function setupWeeklyReportSchedule(client: Client): Promise<void> {
try {
const scheduleHandle = client.schedule.getHandle(SCHEDULE_ID);

// Check if schedule already exists
try {
await scheduleHandle.describe();
logger.info(`Schedule ${SCHEDULE_ID} already exists, skipping creation`);

return;
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);

// Schedule doesn't exist, create it
logger.info(
`Creating schedule ${SCHEDULE_ID} with error: ${errorMessage}`,
);
}

await client.schedule.create({
scheduleId: SCHEDULE_ID,
spec: {
cronExpressions: ['0 13 * * 2'], // Every Tuesday at 1 PM
timezone: 'America/New_York', // Automatically handles EST/EDT transitions
},
action: {
type: 'startWorkflow',
workflowType: weeklyFinancialReportsWorkflow,
taskQueue: workerConfig.taskQueue,
workflowId: `weekly-financial-report-scheduled`,
},
policies: {
overlap: 'SKIP', // Skip if previous run is still in progress
catchupWindow: '1 day', // Catch up missed runs within 1 day
},
});

logger.info(
`Successfully created schedule ${SCHEDULE_ID} for weekly financial reports`,
);
} catch (error) {
logger.error(
`Failed to setup schedule ${SCHEDULE_ID}: ${error instanceof Error ? error.message : String(error)}`,
);
throw error;
}
}

/**
* Schedule configuration exported for documentation and testing
*/
export const scheduleConfig = {
scheduleId: SCHEDULE_ID,
cronExpression: '0 13 * * 2',
timezone: 'America/New_York',
description: 'Runs every Tuesday at 1 PM EST/EDT',
} as const;
20 changes: 20 additions & 0 deletions workers/main/src/configs/temporal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,30 @@ import { z } from 'zod';

const DEFAULT_TEMPORAL_ADDRESS = 'temporal:7233';

/**
* Temporal connection configuration
* Used by both workers and clients to connect to Temporal server
*/
export const temporalConfig: NativeConnectionOptions = {
address: process.env.TEMPORAL_ADDRESS || DEFAULT_TEMPORAL_ADDRESS,
};

export const temporalSchema = z.object({
TEMPORAL_ADDRESS: z.string().default(DEFAULT_TEMPORAL_ADDRESS),
});

/**
* Schedule Configuration Documentation
*
* Weekly Financial Report Schedule:
* - Schedule ID: 'weekly-financial-report-schedule'
* - Cron Expression: '0 13 * * 2' (Every Tuesday at 1 PM)
* - Timezone: 'America/New_York' (automatically handles EST/EDT transitions)
* - Workflow: weeklyFinancialReportsWorkflow
* - Task Queue: 'main-queue'
* - Overlap Policy: SKIP (prevents concurrent runs)
* - Catchup Window: 1 day (runs missed schedules within 24 hours)
*
* The schedule is automatically created/verified when the worker starts.
* See src/configs/schedules.ts for implementation details.
*/
18 changes: 18 additions & 0 deletions workers/main/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Client, Connection } from '@temporalio/client';
import { DefaultLogger, NativeConnection, Worker } from '@temporalio/worker';

import * as activities from './activities';
import { validateEnv } from './common/utils';
import { setupWeeklyReportSchedule } from './configs/schedules';
import { temporalConfig } from './configs/temporal';
import { workerConfig } from './configs/worker';

Expand All @@ -25,6 +27,22 @@ export async function createWorker(connection: NativeConnection) {
}

export async function run(): Promise<void> {
// Setup weekly report schedule before starting worker
const clientConnection = await Connection.connect(temporalConfig);

try {
const client = new Client({ connection: clientConnection });

await setupWeeklyReportSchedule(client);
} catch (err) {
logger.error(
`Failed to setup schedule: ${err instanceof Error ? err.message : String(err)}`,
);
} finally {
await clientConnection.close();
}

// Create and run worker
const connection = await createConnection();

try {
Expand Down
Loading