chore(repo) init AppSchedule module
This commit is contained in:
parent
ef50d7075f
commit
1b7c586b69
@ -8,6 +8,7 @@ import { EnumifyModule } from './modules/enumify/enumify.module';
|
||||
import { AppFileTransactionsModule } from './modules/file-transactions/file-transactions.module';
|
||||
import { AppHealthModule } from './modules/health/health.module';
|
||||
import { AppLoggerModule } from './modules/logger/logger.module';
|
||||
import { AppScheduleModule } from './modules/schedule/schedule.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -16,6 +17,7 @@ import { AppLoggerModule } from './modules/logger/logger.module';
|
||||
AppDatabaseModule,
|
||||
AppHealthModule,
|
||||
AppFileTransactionsModule,
|
||||
AppScheduleModule,
|
||||
EnumifyModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { DatabaseConfig, databaseConfig } from './database.config';
|
||||
import { APP_DATASOURCES } from './database.constants';
|
||||
import { typeormTransactionalDataSourceFactory } from './utils/typeorm-data-source-factory';
|
||||
import { typeormEntitiesFromImport } from './utils/typeorm-import-entities';
|
||||
import { typeormModuleOptionsFactory } from './utils/typeorm-module-options-factory';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
const dataSources: DataSource[] = [];
|
||||
|
||||
@ -15,10 +14,7 @@ const typeormModules = [
|
||||
imports: databaseConfig.asProvider().imports,
|
||||
dataSourceFactory: typeormTransactionalDataSourceFactory(),
|
||||
useFactory: async (dbConfig: DatabaseConfig) => {
|
||||
// const entities = await import('./path/to/entities');
|
||||
const entities = {};
|
||||
|
||||
const config = await typeormModuleOptionsFactory(dbConfig, [typeormEntitiesFromImport(entities)]);
|
||||
const config = await typeormModuleOptionsFactory(dbConfig);
|
||||
return config;
|
||||
},
|
||||
inject: [databaseConfig.KEY],
|
||||
|
@ -0,0 +1 @@
|
||||
export { TipiJobsEntity } from './tipi_jobs.entity';
|
@ -0,0 +1,50 @@
|
||||
import { Column, Entity, Index } from 'typeorm';
|
||||
import { Enumify } from '../../enumify/enumify';
|
||||
|
||||
export class InviaMailSeErrori {
|
||||
@Column('bit', { name: 'flag', default: () => '(0)' })
|
||||
flagAttivo: boolean;
|
||||
|
||||
@Column('varchar', { name: 'oggetto', nullable: true, length: 255 })
|
||||
oggetto: string | null;
|
||||
|
||||
@Column('varchar', { name: 'destinatari', nullable: true, length: 255 })
|
||||
destinatari: string | null;
|
||||
|
||||
@Column('varchar', { name: 'cc', nullable: true, length: 255 })
|
||||
cc: string | null;
|
||||
}
|
||||
|
||||
@Entity('tipi_jobs')
|
||||
export class TipiJobsEntity extends Enumify {
|
||||
static _ = TipiJobsEntity.closeEnum();
|
||||
|
||||
// Columns
|
||||
|
||||
@Column('int', { primary: true, name: 'id' })
|
||||
id: number;
|
||||
|
||||
@Column('varchar', { name: 'nome', length: 50 })
|
||||
nome: string;
|
||||
|
||||
@Column('varchar', { name: 'descrizione', nullable: true, length: 255 })
|
||||
descrizione: string | null;
|
||||
|
||||
@Column(() => InviaMailSeErrori, { prefix: 'invia_mail_se_errori'})
|
||||
inviaMailSeErrori: InviaMailSeErrori;
|
||||
|
||||
@Column('bit', { name: 'flag_attivo', default: () => '(0)' })
|
||||
flagAttivo: boolean;
|
||||
|
||||
@Column('varchar', { name: 'pattern_cron', length: 20 })
|
||||
patternCron: string;
|
||||
|
||||
public constructor(
|
||||
id: number,
|
||||
nome: string,
|
||||
patternCron: string,
|
||||
) {
|
||||
super(id, nome);
|
||||
this.patternCron = patternCron;
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||
import { DatabaseConfig } from '../database.config';
|
||||
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
||||
|
||||
export const typeormModuleOptionsFactory = async (
|
||||
databaseConfig: DatabaseConfig,
|
||||
entities: any[],
|
||||
name?: string
|
||||
): Promise<TypeOrmModuleOptions> => {
|
||||
return {
|
||||
@ -14,9 +14,10 @@ export const typeormModuleOptionsFactory = async (
|
||||
username: databaseConfig.username,
|
||||
password: databaseConfig.password,
|
||||
database: databaseConfig.database,
|
||||
entities: [...entities],
|
||||
autoLoadEntities: true,
|
||||
synchronize: false,
|
||||
logging: process.env['NODE_ENV'] !== 'production',
|
||||
namingStrategy: new SnakeNamingStrategy(),
|
||||
options: {
|
||||
...(!databaseConfig.secure ? { trustServerCertificate: true } : {}),
|
||||
},
|
||||
|
12
apps/ebitemp-api/src/app/modules/schedule/schedule.module.ts
Normal file
12
apps/ebitemp-api/src/app/modules/schedule/schedule.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ScheduleModule } from '@nestjs/schedule';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { TipiJobsEntity } from '../database/entities';
|
||||
import { SchedulerService } from './schedule.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([TipiJobsEntity]), ScheduleModule.forRoot()],
|
||||
providers: [SchedulerService],
|
||||
exports: [],
|
||||
})
|
||||
export class AppScheduleModule {}
|
@ -0,0 +1,52 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { CronJob, CronTime } from 'cron';
|
||||
import { Repository } from 'typeorm';
|
||||
import { TipiJobsEntity } from '../database/entities/tipi_jobs.entity';
|
||||
|
||||
@Injectable()
|
||||
export class SchedulerService {
|
||||
private readonly logger = new Logger(SchedulerService.name);
|
||||
|
||||
private static readonly TIME_ZONE = 'Europe/Rome';
|
||||
|
||||
constructor(
|
||||
private readonly schedulerRegistry: SchedulerRegistry,
|
||||
@InjectRepository(TipiJobsEntity) private readonly tipiJobsRepository: Repository<TipiJobsEntity>
|
||||
) {}
|
||||
|
||||
async onApplicationBootstrap() {
|
||||
try {
|
||||
const jobs = this.schedulerRegistry.getCronJobs();
|
||||
const jobTypes = await this.tipiJobsRepository.find();
|
||||
|
||||
for (const [jobName, job] of jobs) {
|
||||
this.rescheduleJobAccordingToJobType(jobTypes, jobName, job);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error(err.message);
|
||||
this.logger.warn(`Error while retrieving scheduled jobs on database. Skipping jobs.`);
|
||||
}
|
||||
}
|
||||
|
||||
private rescheduleJobAccordingToJobType(jobTypes: TipiJobsEntity[], jobName: string, job: CronJob) {
|
||||
const jobType = jobTypes.find((jobType) => jobType.nome == jobName);
|
||||
|
||||
if (!jobType) {
|
||||
this.logger.warn(`Job type for job '${jobName}' not found on database. Skipping job.`);
|
||||
this.schedulerRegistry.deleteCronJob(jobName);
|
||||
return;
|
||||
}
|
||||
|
||||
const jobTime = new CronTime(jobType.patternCron, SchedulerService.TIME_ZONE);
|
||||
job.setTime(jobTime);
|
||||
job.start();
|
||||
|
||||
this.logger.log(
|
||||
`Job type id '${jobType.id}' found for job '${jobName}' [isActive: ${jobType.flagAttivo}, cronPattern: ${
|
||||
jobType.patternCron
|
||||
}]. Upcoming date => ${job.nextDate()}`
|
||||
);
|
||||
}
|
||||
}
|
@ -18,12 +18,14 @@
|
||||
"@nestjs/core": "^11.0.8",
|
||||
"@nestjs/platform-express": "^11.0.8",
|
||||
"@nestjs/platform-fastify": "^11.0.8",
|
||||
"@nestjs/schedule": "^5.0.1",
|
||||
"@nestjs/terminus": "^11.0.0",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"@nx/devkit": "20.4.2",
|
||||
"axios": "^1.7.9",
|
||||
"cacheable": "^1.8.8",
|
||||
"connection-string": "^4.4.0",
|
||||
"cron": "^3.5.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"flatted": "^3.3.2",
|
||||
"lodash": "^4.17.21",
|
||||
@ -34,6 +36,7 @@
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"typeorm": "^0.3.20",
|
||||
"typeorm-naming-strategies": "^4.1.0",
|
||||
"typeorm-scoped": "^1.2.0",
|
||||
"typeorm-transactional": "^0.5.0",
|
||||
"zod": "^3.24.1"
|
||||
|
44
pnpm-lock.yaml
generated
44
pnpm-lock.yaml
generated
@ -29,6 +29,9 @@ dependencies:
|
||||
'@nestjs/platform-fastify':
|
||||
specifier: ^11.0.8
|
||||
version: 11.0.8(@nestjs/common@11.0.8)(@nestjs/core@11.0.8)
|
||||
'@nestjs/schedule':
|
||||
specifier: ^5.0.1
|
||||
version: 5.0.1(@nestjs/common@11.0.8)(@nestjs/core@11.0.8)
|
||||
'@nestjs/terminus':
|
||||
specifier: ^11.0.0
|
||||
version: 11.0.0(@nestjs/common@11.0.8)(@nestjs/core@11.0.8)(@nestjs/typeorm@11.0.0)(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20)
|
||||
@ -47,6 +50,9 @@ dependencies:
|
||||
connection-string:
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0
|
||||
cron:
|
||||
specifier: ^3.5.0
|
||||
version: 3.5.0
|
||||
dayjs:
|
||||
specifier: ^1.11.13
|
||||
version: 1.11.13
|
||||
@ -77,6 +83,9 @@ dependencies:
|
||||
typeorm:
|
||||
specifier: ^0.3.20
|
||||
version: 0.3.20(mssql@11.0.1)(ts-node@10.9.2)
|
||||
typeorm-naming-strategies:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0(typeorm@0.3.20)
|
||||
typeorm-scoped:
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0(typeorm@0.3.20)
|
||||
@ -2524,6 +2533,17 @@ packages:
|
||||
tslib: 2.8.1
|
||||
dev: false
|
||||
|
||||
/@nestjs/schedule@5.0.1(@nestjs/common@11.0.8)(@nestjs/core@11.0.8):
|
||||
resolution: {integrity: sha512-kFoel84I4RyS2LNPH6yHYTKxB16tb3auAEciFuc788C3ph6nABkUfzX5IE+unjVaRX+3GuruJwurNepMlHXpQg==}
|
||||
peerDependencies:
|
||||
'@nestjs/common': ^10.0.0 || ^11.0.0
|
||||
'@nestjs/core': ^10.0.0 || ^11.0.0
|
||||
dependencies:
|
||||
'@nestjs/common': 11.0.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
'@nestjs/core': 11.0.8(@nestjs/common@11.0.8)(@nestjs/platform-express@11.0.8)(reflect-metadata@0.2.2)(rxjs@7.8.1)
|
||||
cron: 3.5.0
|
||||
dev: false
|
||||
|
||||
/@nestjs/schematics@11.0.0(typescript@5.7.3):
|
||||
resolution: {integrity: sha512-wts8lG0GfNWw3Wk9aaG5I/wcMIAdm7HjjeThQfUZhJxeIFT82Z3F5+0cYdHH4ii2pYQGiCSrR1VcuMwPiHoecg==}
|
||||
peerDependencies:
|
||||
@ -3794,6 +3814,10 @@ packages:
|
||||
resolution: {integrity: sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==}
|
||||
dev: true
|
||||
|
||||
/@types/luxon@3.4.2:
|
||||
resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
|
||||
dev: false
|
||||
|
||||
/@types/mime@1.3.5:
|
||||
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
|
||||
dev: true
|
||||
@ -5308,6 +5332,13 @@ packages:
|
||||
/create-require@1.1.1:
|
||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||
|
||||
/cron@3.5.0:
|
||||
resolution: {integrity: sha512-0eYZqCnapmxYcV06uktql93wNWdlTmmBFP2iYz+JPVcQqlyFYcn1lFuIk4R54pkOmE7mcldTAPZv6X5XA4Q46A==}
|
||||
dependencies:
|
||||
'@types/luxon': 3.4.2
|
||||
luxon: 3.5.0
|
||||
dev: false
|
||||
|
||||
/cross-spawn@5.1.0:
|
||||
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
|
||||
dependencies:
|
||||
@ -8082,6 +8113,11 @@ packages:
|
||||
yallist: 3.1.1
|
||||
dev: true
|
||||
|
||||
/luxon@3.5.0:
|
||||
resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/magic-string@0.30.0:
|
||||
resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==}
|
||||
engines: {node: '>=12'}
|
||||
@ -10875,6 +10911,14 @@ packages:
|
||||
- typeorm-aurora-data-api-driver
|
||||
dev: true
|
||||
|
||||
/typeorm-naming-strategies@4.1.0(typeorm@0.3.20):
|
||||
resolution: {integrity: sha512-vPekJXzZOTZrdDvTl1YoM+w+sUIfQHG4kZTpbFYoTsufyv9NIBRe4Q+PdzhEAFA2std3D9LZHEb1EjE9zhRpiQ==}
|
||||
peerDependencies:
|
||||
typeorm: ^0.2.0 || ^0.3.0
|
||||
dependencies:
|
||||
typeorm: 0.3.20(mssql@11.0.1)(ts-node@10.9.2)
|
||||
dev: false
|
||||
|
||||
/typeorm-scoped@1.2.0(typeorm@0.3.20):
|
||||
resolution: {integrity: sha512-fVZUFIAHCib6Sq/k1wGzwtnFb9uP+g/hLDaoosczJpSNAG2YA2CyPR5J3+UuTz11kvdAfQO0Udk+6rL8xX2/Wg==}
|
||||
peerDependencies:
|
||||
|
Reference in New Issue
Block a user