Switch email provider from Resend to Mailgun and add cron scheduler
Some checks failed
Deploy / deploy (push) Failing after 1m43s
Some checks failed
Deploy / deploy (push) Failing after 1m43s
- Replace resend package with mailgun.js and form-data - Update email.ts to use Mailgun API with lazy client initialization - Add instrumentation.ts to schedule cron jobs (notifications :00, Garmin :30) - Update tests for Mailgun mock structure - Update .env.example with MAILGUN_API_KEY and MAILGUN_DOMAIN Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
62
src/instrumentation.ts
Normal file
62
src/instrumentation.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
// ABOUTME: Next.js instrumentation file for server startup initialization.
|
||||
// ABOUTME: Schedules cron jobs for notifications and Garmin sync using node-cron.
|
||||
|
||||
export async function register() {
|
||||
// Only run on the server side
|
||||
if (process.env.NEXT_RUNTIME === "nodejs") {
|
||||
const cron = await import("node-cron");
|
||||
|
||||
const APP_URL = process.env.APP_URL || "http://localhost:3000";
|
||||
const CRON_SECRET = process.env.CRON_SECRET;
|
||||
|
||||
// Log startup
|
||||
console.log("[cron] Scheduler starting...");
|
||||
|
||||
if (!CRON_SECRET) {
|
||||
console.warn(
|
||||
"[cron] CRON_SECRET not set - cron jobs will fail authentication",
|
||||
);
|
||||
}
|
||||
|
||||
// Helper to call cron endpoints
|
||||
async function triggerCronEndpoint(endpoint: string, name: string) {
|
||||
try {
|
||||
const response = await fetch(`${APP_URL}/api/cron/${endpoint}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${CRON_SECRET}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error(
|
||||
`[cron] ${name} failed: ${response.status} ${errorText}`,
|
||||
);
|
||||
} else {
|
||||
const result = await response.json();
|
||||
console.log(`[cron] ${name} completed:`, result);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[cron] ${name} error:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule notifications at the top of every hour
|
||||
cron.default.schedule("0 * * * *", () => {
|
||||
console.log("[cron] Triggering notifications...");
|
||||
triggerCronEndpoint("notifications", "Notifications");
|
||||
});
|
||||
|
||||
// Schedule Garmin sync at 30 minutes past every hour
|
||||
cron.default.schedule("30 * * * *", () => {
|
||||
console.log("[cron] Triggering Garmin sync...");
|
||||
triggerCronEndpoint("garmin-sync", "Garmin sync");
|
||||
});
|
||||
|
||||
console.log(
|
||||
"[cron] Scheduler started - notifications at :00, Garmin sync at :30",
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user