14064 extensibility add coretriggereventlistener table (#14138)
This Pr continues the extensibility journey - adds a `core.databaseEventTrigger` table - add a oneToMany relation between `core.serverlessFunction` and `core.databaseEventTrigger` - add a job `CallDatabaseEventTriggerJobsJob` triggered by `EntityEventsToDbListener` triggering `serverlessFunction` based on the `core.databaseEventTrigger.settings.eventName` - add a new `trigger-queue` to carry this job - renamed `DatabaseEventTriggerListener` into `WorkflowDatabaseEventTriggerListener`
This commit is contained in:
+10
@@ -12,6 +12,7 @@ import {
|
||||
|
||||
import { InputSchema } from 'src/modules/workflow/workflow-builder/workflow-schema/types/input-schema.type';
|
||||
import { CronTrigger } from 'src/engine/metadata-modules/trigger/entities/cron-trigger.entity';
|
||||
import { DatabaseEventTrigger } from 'src/engine/metadata-modules/trigger/entities/database-event-trigger.entity';
|
||||
|
||||
const DEFAULT_SERVERLESS_TIMEOUT_SECONDS = 300; // 5 minutes
|
||||
|
||||
@@ -63,6 +64,15 @@ export class ServerlessFunctionEntity {
|
||||
)
|
||||
cronTriggers: CronTrigger[];
|
||||
|
||||
@OneToMany(
|
||||
() => DatabaseEventTrigger,
|
||||
(databaseEventTrigger) => databaseEventTrigger.serverlessFunction,
|
||||
{
|
||||
cascade: true,
|
||||
},
|
||||
)
|
||||
databaseEventTriggers: DatabaseEventTrigger[];
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
+2
-2
@@ -48,7 +48,7 @@ export class CronTriggerCronJob {
|
||||
where: {
|
||||
workspaceId: activeWorkspace.id,
|
||||
},
|
||||
select: ['settings'],
|
||||
select: ['id', 'settings', 'workspaceId'],
|
||||
relations: ['serverlessFunction'],
|
||||
});
|
||||
|
||||
@@ -67,7 +67,7 @@ export class CronTriggerCronJob {
|
||||
ServerlessFunctionTriggerJob.name,
|
||||
{
|
||||
serverlessFunctionId: cronTrigger.serverlessFunction.id,
|
||||
workspaceId: activeWorkspace.id,
|
||||
workspaceId: cronTrigger.workspaceId,
|
||||
payload: {},
|
||||
},
|
||||
{ retryLimit: 3 },
|
||||
|
||||
+3
-1
@@ -11,6 +11,8 @@ import {
|
||||
Index,
|
||||
} from 'typeorm';
|
||||
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/interfaces/syncable-entity.interface';
|
||||
|
||||
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
|
||||
export type CronTriggerSettings = {
|
||||
@@ -19,7 +21,7 @@ export type CronTriggerSettings = {
|
||||
|
||||
@Entity({ name: 'cronTrigger', schema: 'core' })
|
||||
@Index('IDX_CRON_TRIGGER_WORKSPACE_ID', ['workspaceId'])
|
||||
export class CronTrigger {
|
||||
export class CronTrigger extends SyncableEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
DeleteDateColumn,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
Relation,
|
||||
Index,
|
||||
} from 'typeorm';
|
||||
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/interfaces/syncable-entity.interface';
|
||||
|
||||
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
|
||||
export type DatabaseEventTriggerSettings = {
|
||||
eventName: string;
|
||||
};
|
||||
|
||||
@Entity({ name: 'databaseEventTrigger', schema: 'core' })
|
||||
@Index('IDX_DATABASE_EVENT_TRIGGER_WORKSPACE_ID', ['workspaceId'])
|
||||
export class DatabaseEventTrigger extends SyncableEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ nullable: false, type: 'jsonb' })
|
||||
settings: DatabaseEventTriggerSettings;
|
||||
|
||||
@ManyToOne(
|
||||
() => ServerlessFunctionEntity,
|
||||
(serverlessFunction) => serverlessFunction.databaseEventTriggers,
|
||||
{ onDelete: 'CASCADE' },
|
||||
)
|
||||
@JoinColumn({ name: 'serverlessFunctionId' })
|
||||
serverlessFunction: Relation<ServerlessFunctionEntity>;
|
||||
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
workspaceId: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt: Date;
|
||||
|
||||
@DeleteDateColumn({ type: 'timestamptz' })
|
||||
deletedAt?: Date;
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
|
||||
import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type';
|
||||
import type { ObjectRecordEvent } from 'src/engine/core-modules/event-emitter/types/object-record-event.event';
|
||||
import { DatabaseEventTrigger } from 'src/engine/metadata-modules/trigger/entities/database-event-trigger.entity';
|
||||
import {
|
||||
ServerlessFunctionTriggerJob,
|
||||
ServerlessFunctionTriggerJobData,
|
||||
} from 'src/engine/metadata-modules/serverless-function/jobs/serverless-function-trigger.job';
|
||||
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
|
||||
@Processor(MessageQueue.triggerQueue)
|
||||
export class CallDatabaseEventTriggerJobsJob {
|
||||
constructor(
|
||||
@InjectMessageQueue(MessageQueue.serverlessFunctionQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
@InjectRepository(DatabaseEventTrigger)
|
||||
private readonly databaseEventTriggerRepository: Repository<DatabaseEventTrigger>,
|
||||
) {}
|
||||
|
||||
@Process(CallDatabaseEventTriggerJobsJob.name)
|
||||
async handle(workspaceEventBatch: WorkspaceEventBatch<ObjectRecordEvent>) {
|
||||
const databaseEventListeners =
|
||||
await this.databaseEventTriggerRepository.find({
|
||||
where: {
|
||||
workspaceId: workspaceEventBatch.workspaceId,
|
||||
},
|
||||
select: ['id', 'settings', 'workspaceId'],
|
||||
relations: ['serverlessFunction'],
|
||||
});
|
||||
|
||||
for (const databaseEventListener of databaseEventListeners) {
|
||||
if (
|
||||
!this.shouldTriggerJob({
|
||||
workspaceEventBatch,
|
||||
eventName: databaseEventListener.settings.eventName,
|
||||
})
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const eventData of workspaceEventBatch.events) {
|
||||
await this.messageQueueService.add<ServerlessFunctionTriggerJobData>(
|
||||
ServerlessFunctionTriggerJob.name,
|
||||
{
|
||||
serverlessFunctionId: databaseEventListener.serverlessFunction.id,
|
||||
workspaceId: databaseEventListener.workspaceId,
|
||||
payload: eventData,
|
||||
},
|
||||
{ retryLimit: 3 },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private shouldTriggerJob({
|
||||
workspaceEventBatch,
|
||||
eventName,
|
||||
}: {
|
||||
workspaceEventBatch: WorkspaceEventBatch<ObjectRecordEvent>;
|
||||
eventName: string;
|
||||
}) {
|
||||
const [nameSingular, operation] = workspaceEventBatch.name.split('.');
|
||||
|
||||
const validEventNames = [
|
||||
`${nameSingular}.${operation}`,
|
||||
`*.${operation}`,
|
||||
`${nameSingular}.*`,
|
||||
'*.*',
|
||||
];
|
||||
|
||||
return validEventNames.includes(eventName);
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,18 @@ import { CronTriggerCronCommand } from 'src/engine/metadata-modules/trigger/cron
|
||||
import { CronTriggerCronJob } from 'src/engine/metadata-modules/trigger/crons/jobs/cron-trigger.cron.job';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { CronTrigger } from 'src/engine/metadata-modules/trigger/entities/cron-trigger.entity';
|
||||
import { CallDatabaseEventTriggerJobsJob } from 'src/engine/metadata-modules/trigger/jobs/call-database-event-trigger-jobs.job';
|
||||
import { DatabaseEventTrigger } from 'src/engine/metadata-modules/trigger/entities/database-event-trigger.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Workspace, CronTrigger])],
|
||||
providers: [CronTriggerCronJob, CronTriggerCronCommand],
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Workspace, CronTrigger, DatabaseEventTrigger]),
|
||||
],
|
||||
providers: [
|
||||
CronTriggerCronJob,
|
||||
CronTriggerCronCommand,
|
||||
CallDatabaseEventTriggerJobsJob,
|
||||
],
|
||||
exports: [CronTriggerCronCommand],
|
||||
})
|
||||
export class TriggerModule {}
|
||||
|
||||
Reference in New Issue
Block a user