diff --git a/src/app.module.ts b/src/app.module.ts index fc16e241..fa029cc8 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -72,6 +72,7 @@ import { UserAtprotoIdentityModule } from './user-atproto-identity/user-atproto- import { AtprotoIdentityModule } from './atproto-identity/atproto-identity.module'; import { MeModule } from './me/me.module'; import { DIDApiModule } from './did-api/did-api.module'; +import { ScheduleModule } from '@nestjs/schedule'; const infrastructureDatabaseModule = TypeOrmModule.forRootAsync({ useClass: TypeOrmConfigService, @@ -123,6 +124,15 @@ const infrastructureDatabaseModule = TypeOrmModule.forRootAsync({ inject: [ConfigService], }), EventEmitterModule.forRoot(), + // The ONLY ScheduleModule registration in the application. forRoot() sets + // global: true and its ScheduleExplorer scans every provider in the + // container, so feature modules import nothing and their @Cron methods are + // still discovered. Two rules follow: calling forRoot() in more than one + // module creates one ScheduleExplorer per call site and fires every cron + // once per call site; and importing the BARE ScheduleModule creates a + // second module whose SchedulerOrchestrator cannot resolve + // SchedulerRegistry (only forRoot() provides it), which fails bootstrap. + ScheduleModule.forRoot(), ThrottlerModule.forRoot([ { ttl: 60000, // 60 seconds diff --git a/src/atproto-publisher/atproto-publisher.module.ts b/src/atproto-publisher/atproto-publisher.module.ts index 80eda38e..3b44c6a9 100644 --- a/src/atproto-publisher/atproto-publisher.module.ts +++ b/src/atproto-publisher/atproto-publisher.module.ts @@ -1,5 +1,4 @@ import { Module, forwardRef } from '@nestjs/common'; -import { ScheduleModule } from '@nestjs/schedule'; import { AtprotoPublisherService } from './atproto-publisher.service'; import { AtprotoSyncScheduler } from './atproto-sync-scheduler'; import { PdsModule } from '../pds/pds.module'; @@ -31,7 +30,8 @@ import { TenantModule } from '../tenant/tenant.module'; */ @Module({ imports: [ - ScheduleModule.forRoot(), + // @Cron methods are discovered by the single global + // ScheduleModule.forRoot() in AppModule; no import is needed here. PdsModule, forwardRef(() => BlueskyModule), AtprotoIdentityModule, diff --git a/src/database/database-metrics.module.ts b/src/database/database-metrics.module.ts index e739b3a5..c442d0c5 100644 --- a/src/database/database-metrics.module.ts +++ b/src/database/database-metrics.module.ts @@ -1,5 +1,4 @@ import { Module } from '@nestjs/common'; -import { ScheduleModule } from '@nestjs/schedule'; import { DatabaseMetricsService } from './database-metrics.service'; import { makeGaugeProvider, @@ -57,7 +56,6 @@ const databaseMetricsProviders = [ ]; @Module({ - imports: [ScheduleModule], providers: [DatabaseMetricsService, ...databaseMetricsProviders], exports: [DatabaseMetricsService, ...databaseMetricsProviders], }) diff --git a/src/external-calendar/external-calendar.module.ts b/src/external-calendar/external-calendar.module.ts index 9a8bd69c..c1e11ff9 100644 --- a/src/external-calendar/external-calendar.module.ts +++ b/src/external-calendar/external-calendar.module.ts @@ -1,5 +1,4 @@ import { Module } from '@nestjs/common'; -import { ScheduleModule } from '@nestjs/schedule'; import { ExternalCalendarService } from './external-calendar.service'; import { ExternalCalendarController } from './external-calendar.controller'; import { AvailabilityController } from './availability.controller'; @@ -10,7 +9,9 @@ import { CalendarSourceModule } from '../calendar-source/calendar-source.module' import { TenantModule } from '../tenant/tenant.module'; @Module({ - imports: [ScheduleModule.forRoot(), TenantModule, CalendarSourceModule], + // @Cron methods are discovered by the single global + // ScheduleModule.forRoot() in AppModule; no import is needed here. + imports: [TenantModule, CalendarSourceModule], controllers: [ExternalCalendarController, AvailabilityController], providers: [ ExternalCalendarService, diff --git a/src/matrix/matrix.module.ts b/src/matrix/matrix.module.ts index fbca1ae9..6e4b72cf 100644 --- a/src/matrix/matrix.module.ts +++ b/src/matrix/matrix.module.ts @@ -1,6 +1,5 @@ import { Module, forwardRef } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; -import { ScheduleModule } from '@nestjs/schedule'; import { TerminusModule } from '@nestjs/terminus'; import { MatrixController } from './matrix.controller'; import { MatrixAppServiceController } from './controllers/matrix-appservice.controller'; @@ -37,7 +36,6 @@ configureMatrixLogging(); imports: [ ConfigModule.forFeature(matrixConfig), TerminusModule, - ScheduleModule.forRoot(), forwardRef(() => UserModule), TenantModule, forwardRef(() => AuthModule), diff --git a/src/metrics/metrics.module.ts b/src/metrics/metrics.module.ts index b149d149..7914e575 100644 --- a/src/metrics/metrics.module.ts +++ b/src/metrics/metrics.module.ts @@ -1,6 +1,5 @@ import { Module, OnModuleInit } from '@nestjs/common'; import { MetricsService } from './metrics.service'; -import { ScheduleModule } from '@nestjs/schedule'; import { PrometheusModule, makeGaugeProvider, @@ -149,7 +148,8 @@ const atprotoHandleMetrics = [ @Module({ imports: [ - ScheduleModule.forRoot(), + // @Cron methods are discovered by the single global + // ScheduleModule.forRoot() in AppModule; no import is needed here. PrometheusModule.register({ defaultMetrics: { enabled: true,