Merge pull request 'fix(jobs): gate lifecycle-email cron to prod host only' (#97) from fix/lifecycle-cron-prod-only into main
Reviewed-on: #97
This commit was merged in pull request #97.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { Inject, Module, type OnModuleDestroy, type OnModuleInit } from "@nestjs/common";
|
||||
import { Queue } from "bullmq";
|
||||
import { CategoriesModule } from "../categories/categories.module";
|
||||
import { isCatalogBackfillEnabled } from "./prefetch-utils";
|
||||
import { isCatalogBackfillEnabled, isLifecycleEmailEnabled } from "./prefetch-utils";
|
||||
import { PrefetchWorkerService } from "./prefetch-worker.service";
|
||||
import {
|
||||
CATALOG_PREFETCH_QUEUE,
|
||||
@@ -76,19 +76,29 @@ export class JobsModule implements OnModuleInit, OnModuleDestroy {
|
||||
|
||||
// Lifecycle e-mails (trial-ending + win-back): every day at 9:00 AM.
|
||||
// Daytime so the e-mails land at a reasonable hour for recipients.
|
||||
await this.lifecycleEmailQueue.upsertJobScheduler(
|
||||
"lifecycle-email-daily",
|
||||
{ pattern: "0 9 * * *" },
|
||||
{
|
||||
name: "lifecycle-email-run",
|
||||
data: {},
|
||||
opts: {
|
||||
removeOnComplete: { count: 30 },
|
||||
removeOnFail: { count: 100 },
|
||||
// PRODUCTION (sase.tr) ONLY: dev.sase.tr is a separate DB seeded from prod,
|
||||
// so an ungated cron there would send duplicate real-customer mails. Gate
|
||||
// on the prod host (same pattern as catalog-backfill below).
|
||||
if (isLifecycleEmailEnabled()) {
|
||||
await this.lifecycleEmailQueue.upsertJobScheduler(
|
||||
"lifecycle-email-daily",
|
||||
{ pattern: "0 9 * * *" },
|
||||
{
|
||||
name: "lifecycle-email-run",
|
||||
data: {},
|
||||
opts: {
|
||||
removeOnComplete: { count: 30 },
|
||||
removeOnFail: { count: 100 },
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
console.log("[jobs] Registered lifecycle-email cron: 0 9 * * *");
|
||||
);
|
||||
console.log("[jobs] Registered lifecycle-email cron: 0 9 * * *");
|
||||
} else {
|
||||
// Clean up any stale scheduler (e.g. previously registered on dev) so it
|
||||
// doesn't keep firing from Redis after this gate is added.
|
||||
await this.lifecycleEmailQueue.removeJobScheduler("lifecycle-email-daily").catch(() => {});
|
||||
console.log("[jobs] Skipped lifecycle-email cron (not prod host)");
|
||||
}
|
||||
|
||||
// Catalog backfill: every hour at :00. Scans for decoded vehicles whose catalog
|
||||
// isn't fully prefetched and queues them. Self-throttled (queue-depth guard),
|
||||
|
||||
@@ -18,6 +18,23 @@ export function isCatalogBackfillEnabled(): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* True ONLY on the real production deployment (sase.tr).
|
||||
*
|
||||
* Same rationale as {@link isCatalogBackfillEnabled} — both prod and dev run
|
||||
* with `NODE_ENV=production`, so we gate on the prod host. Without this gate
|
||||
* the dev deploy would send duplicate trial-ending / win-back e-mails to real
|
||||
* users (sase_dev DB is a copy of prod data). An explicit
|
||||
* `LIFECYCLE_EMAIL_ENABLED` env wins (e.g. to force-test on staging).
|
||||
*/
|
||||
export function isLifecycleEmailEnabled(): boolean {
|
||||
const flag = process.env.LIFECYCLE_EMAIL_ENABLED;
|
||||
if (flag != null && flag !== "") return flag === "true";
|
||||
return (
|
||||
process.env.COOLIFY_FQDN === "sase.tr" || process.env.BETTER_AUTH_URL === "https://sase.tr"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals the worker that this job is rate-limited and should be deferred.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user