ddd-ts-kit/scheduling-job-triggers-use-case
Architecture id: scheduling/job-triggers-use-case. Default severity: error in recommended, error in strict.
Applies to: production files of a context.
A job is a schedule, not a use case. It sends a command, and the work is in the handler of that command, where it is authorized, transactional, audited and tested like any other use case, and where an operator can also trigger it by hand. A job that loads aggregates and saves them is a use case that escaped all of that.
Reported
Section titled “Reported”In application/scheduling/*.job.ts:
- no exported class implementing
ScheduledJob - a
runmethod that calls no<something>.execute(..), or norunmethod - a repository (a class imported from
domain/repositories/) in the dependency list or as the type of a constructor parameter - an import from
domain/aggregates/,domain/entities/,domain/services/orinfrastructure/
Anywhere else in a context:
- a class carrying
@Scheduled job(..).handledBy(Class, ..)naming a class imported from a file that is notapplication/scheduling/*.job.ts
Incorrect:
@Scheduled('billing.send-reminders', { every: '15m' })export class SendRemindersJob implements ScheduledJob { constructor( private readonly invoices: InvoiceRepository, private readonly mailer: Mailer, ) {}
async run(): Promise<void> { for (const invoice of await this.invoices.overdue()) { await this.mailer.remind(invoice); } }}Correct:
@Scheduled('billing.send-reminders', { every: '15m' })export class SendRemindersJob implements ScheduledJob { constructor(private readonly commands: CommandBus) {}
async run(execution: JobExecution): Promise<void> { await this.commands.execute(new SendRemindersCommand(systemActor('billing.send-reminders'), execution.scheduledAt)); }}Details
Section titled “Details”The rule holds in both styles: an explicit-style job is the same class without @Scheduled, registered by builder.job('<context>.<job>', schedule).handledBy(Job, [CommandBus]) in the module file. Value objects, events, errors and the commands of application/commands/ may be imported by a job. That a job file of a declared-style project carries @Scheduled is declarations/role-declared.
Options
Section titled “Options”None.
rules."scheduling/job-triggers-use-case" in ddd-ts-kit.config.json set to off silences the rule, and // ddd-ts-kit-disable-next-line scheduling/job-triggers-use-case -- <reason> silences one line, exactly as for ddd-ts-kit check.
Limits
Section titled “Limits”- A command sent through a helper of another file (
this.trigger()) is not seen: callexecuteinrun. - A job registered with
handledByFactorynames no class and is not followed. - A class carrying
@Scheduledoutside a context (the platform) is not judged.
With the CLI checker
Section titled “With the CLI checker”ddd-ts-kit check reports the same id from the text of the files. This rule is the authority for the code.