82 lines
2.2 KiB
TypeScript
82 lines
2.2 KiB
TypeScript
import { config } from "./config.js";
|
|
import { listUpcomingDeadlines } from "./contractsStore.js";
|
|
import { createLogger } from "./logger.js";
|
|
import { composeDeadlineNotification, sendDeadlineNotifications } from "./notifications.js";
|
|
import { getRuntimeSettings } from "./runtimeSettings.js";
|
|
|
|
const logger = createLogger(config.logLevel);
|
|
|
|
export class DeadlineMonitor {
|
|
private timer: NodeJS.Timeout | null = null;
|
|
private running = false;
|
|
|
|
start() {
|
|
if (this.running) {
|
|
return;
|
|
}
|
|
this.running = true;
|
|
const settings = getRuntimeSettings();
|
|
logger.info(
|
|
`Starting deadline monitor (interval=${settings.schedulerIntervalMinutes} min, alert window=${settings.alertDaysBefore} days)`
|
|
);
|
|
this.scheduleNext(1000);
|
|
}
|
|
|
|
stop() {
|
|
if (!this.running) {
|
|
return;
|
|
}
|
|
this.running = false;
|
|
if (this.timer) {
|
|
clearTimeout(this.timer);
|
|
this.timer = null;
|
|
}
|
|
logger.info("Deadline monitor stopped.");
|
|
}
|
|
|
|
private scheduleNext(delayMs?: number) {
|
|
if (!this.running) {
|
|
return;
|
|
}
|
|
const settings = getRuntimeSettings();
|
|
const intervalMs = Math.max(settings.schedulerIntervalMinutes, 5) * 60 * 1000;
|
|
const wait = delayMs ?? intervalMs;
|
|
|
|
this.timer = setTimeout(() => {
|
|
this.runCheck()
|
|
.catch((error) => {
|
|
logger.error("Deadline check failed", error);
|
|
})
|
|
.finally(() => {
|
|
this.scheduleNext();
|
|
});
|
|
}, wait);
|
|
}
|
|
|
|
private async runCheck() {
|
|
const settings = getRuntimeSettings();
|
|
const deadlines = listUpcomingDeadlines(settings.alertDaysBefore);
|
|
|
|
if (deadlines.length === 0) {
|
|
logger.debug("No upcoming deadlines within alert window.");
|
|
return;
|
|
}
|
|
|
|
for (const item of deadlines) {
|
|
logger.warn(
|
|
"Upcoming deadline: %s (provider=%s, documentId=%s, terminate by %s, days=%s)",
|
|
item.title,
|
|
item.provider ?? "n/a",
|
|
item.paperlessDocumentId ?? "n/a",
|
|
item.terminationDeadline ?? "n/a",
|
|
item.daysUntilDeadline ?? "n/a"
|
|
);
|
|
}
|
|
|
|
const notification = composeDeadlineNotification(deadlines, settings);
|
|
await sendDeadlineNotifications(notification, settings);
|
|
}
|
|
}
|
|
|
|
export const deadlineMonitor = new DeadlineMonitor();
|