feat(10-04): implement TenderSchedulerService — single global cron (poll-once-fan-out-many)

- One named cron job 'tender-doe-poll' for the whole platform; setInterval()
  takes no tenant argument (INGEST-06) — reuses DkvSchedulerService's
  CronJob require()-resolution + SchedulerRegistry mechanics, drops the
  per-tenant activeTenantId framing entirely
- onModuleInit() loads the singleton doe-opendata config via findUnique on
  the fixed sourceType slug, never findFirst (Pitfall D)
- Day-cursor gate stays inside TenderIngestionService.pollDueSources() —
  this scheduler only controls cron-tick frequency (Pitfall A separation)
- Registered in TendersModule.providers; ScheduleModule already global via
  AppModule, no re-registration needed
This commit is contained in:
2026-07-21 11:10:21 +02:00
parent 6fb734bf3c
commit 0ba74108db
2 changed files with 153 additions and 1 deletions
+7 -1
View File
@@ -6,6 +6,7 @@ import { DoeOpenDataAdapter } from './adapters/doe-opendata.adapter';
import { seedTendersModule } from './tenders.seed';
import { TenderIngestionService } from './tender-ingestion.service';
import { TenderNormalizerService } from './tender-normalizer.service';
import { TenderSchedulerService } from './tender-scheduler.service';
/**
* NestJS module for the Ausschreibungs-Radar feature.
@@ -26,7 +27,12 @@ import { TenderNormalizerService } from './tender-normalizer.service';
@Module({
imports: [ModuleRegistryModule],
controllers: [],
providers: [DoeOpenDataAdapter, TenderNormalizerService, TenderIngestionService],
providers: [
DoeOpenDataAdapter,
TenderNormalizerService,
TenderIngestionService,
TenderSchedulerService,
],
})
export class TendersModule implements OnModuleInit {
private readonly logger = new Logger(TendersModule.name);