Files
goodgo-platform/apps/api/src/modules/notifications/infrastructure/services/notifications-async.config.ts
Ho Ngoc Hai b3836d8d0f feat(notifications): wire publisher + async feature flag (GOO-173)
Phase 1 step 3 — make NotificationsPublisher available via DI and
introduce the NOTIFICATIONS_ASYNC_ENABLED flag that will gate the
listener cutover.

- NotificationsAsyncConfig: tiny injectable that reads
  NOTIFICATIONS_ASYNC_ENABLED (truthy: 1/true/yes/on, default disabled).
  Callers don't touch process.env directly; per-category rollout can be
  added later without churn in listeners.
- NotificationsModule providers/exports now include NotificationsPublisher
  and NotificationsAsyncConfig so listeners/handlers can inject them.
- Tests (14 specs on the flag + 4 on the publisher = 18 total green):
  * default disabled when unset
  * truthy parsing (1, true, TRUE, yes, on, padded)
  * falsy parsing (false, 0, no, off, empty, unknown)
  * describe() reports human-readable state

No call sites updated yet — next commit migrates the first listener
(PaymentCompletedListener pilot) onto the publisher with the flag check.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-24 14:26:10 +07:00

34 lines
1.2 KiB
TypeScript

/**
* Feature-flag config for the Phase 1 async notifications path (RFC-004 / GOO-173).
*
* When NOTIFICATIONS_ASYNC_ENABLED is `true`, producers route through
* `NotificationsPublisher` → outbox → Redis Streams → BullMQ consumer.
* When `false` (default until parity is confirmed in production), producers
* continue to execute `SendNotificationCommand` directly in-process.
*
* Kept as a tiny injectable so:
* - callers don't read process.env directly (testability)
* - we have one place to evolve the flag shape (per-category rollout,
* percentage shadowing, etc.) without ripping through listeners again
*/
import { Injectable } from '@nestjs/common';
const FLAG_ENV = 'NOTIFICATIONS_ASYNC_ENABLED';
@Injectable()
export class NotificationsAsyncConfig {
/** True when the async outbox path should be used for new notifications. */
get asyncEnabled(): boolean {
const raw = process.env[FLAG_ENV];
if (raw === undefined) return false;
const v = raw.trim().toLowerCase();
return v === '1' || v === 'true' || v === 'yes' || v === 'on';
}
/** Exposed for observability / startup logs. */
describe(): string {
return `${FLAG_ENV}=${this.asyncEnabled ? 'enabled' : 'disabled'}`;
}
}