feat: add campaign configuration controls
This commit is contained in:
103
lib/campaign-scheduling.ts
Normal file
103
lib/campaign-scheduling.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
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";
|
||||
}
|
||||
Reference in New Issue
Block a user