104 lines
2.6 KiB
TypeScript
104 lines
2.6 KiB
TypeScript
import { CAMPAIGN_RECURRENCES, CAMPAIGN_STATUSES } from "./campaign-form";
|
|
|
|
export type CampaignRecurrence = (typeof CAMPAIGN_RECURRENCES)[number];
|
|
export type CampaignStatus = (typeof CAMPAIGN_STATUSES)[number];
|
|
|
|
export type CampaignFormRecurrenceInput = {
|
|
recurrence: CampaignRecurrence | (string & {});
|
|
status: CampaignStatus;
|
|
lastRunAt?: number | null;
|
|
now?: number;
|
|
};
|
|
|
|
export type CampaignRunInfo = {
|
|
campaignStatus: CampaignStatus;
|
|
agentRuns?: Array<{
|
|
status: string;
|
|
updatedAt?: number;
|
|
}>;
|
|
};
|
|
|
|
export function isAllowedCampaignRecurrence(value: string): boolean {
|
|
return CAMPAIGN_RECURRENCES.includes(value as CampaignRecurrence);
|
|
}
|
|
|
|
function addDaysUTC(base: number, days: number): number {
|
|
const date = new Date(base);
|
|
return Date.UTC(
|
|
date.getUTCFullYear(),
|
|
date.getUTCMonth(),
|
|
date.getUTCDate() + days,
|
|
date.getUTCHours(),
|
|
date.getUTCMinutes(),
|
|
date.getUTCSeconds(),
|
|
date.getUTCMilliseconds(),
|
|
);
|
|
}
|
|
|
|
function addMonthsUTC(base: number, months: number): number {
|
|
const date = new Date(base);
|
|
return Date.UTC(
|
|
date.getUTCFullYear(),
|
|
date.getUTCMonth() + months,
|
|
date.getUTCDate(),
|
|
date.getUTCHours(),
|
|
date.getUTCMinutes(),
|
|
date.getUTCSeconds(),
|
|
date.getUTCMilliseconds(),
|
|
);
|
|
}
|
|
|
|
export function calculateNextRunAt(input: CampaignFormRecurrenceInput): number | null {
|
|
if (input.status !== "active") {
|
|
return null;
|
|
}
|
|
|
|
if (!isAllowedCampaignRecurrence(input.recurrence)) {
|
|
return null;
|
|
}
|
|
|
|
if (input.recurrence === "manual") {
|
|
return null;
|
|
}
|
|
|
|
const anchor = input.lastRunAt ?? input.now ?? Date.now();
|
|
if (input.recurrence === "daily") {
|
|
return addDaysUTC(anchor, 1);
|
|
}
|
|
|
|
if (input.recurrence === "weekly") {
|
|
return addDaysUTC(anchor, 7);
|
|
}
|
|
|
|
return addMonthsUTC(anchor, 1);
|
|
}
|
|
|
|
export function getCampaignCurrentRunStatus(input: CampaignRunInfo): string {
|
|
const agentRuns = input.agentRuns ?? [];
|
|
if (agentRuns.length > 0) {
|
|
const ordered = [...agentRuns].sort((a, b) => {
|
|
const aUpdatedAt = typeof a.updatedAt === "number" ? a.updatedAt : 0;
|
|
const bUpdatedAt = typeof b.updatedAt === "number" ? b.updatedAt : 0;
|
|
|
|
return bUpdatedAt - aUpdatedAt;
|
|
});
|
|
|
|
const latestStatus = ordered.at(0)?.status;
|
|
if (latestStatus === "running") {
|
|
return "running";
|
|
}
|
|
if (latestStatus === "pending") {
|
|
return "pending";
|
|
}
|
|
if (
|
|
latestStatus === "succeeded" ||
|
|
latestStatus === "failed" ||
|
|
latestStatus === "canceled"
|
|
) {
|
|
return latestStatus;
|
|
}
|
|
}
|
|
|
|
return input.campaignStatus === "paused" ? "paused" : "idle";
|
|
}
|