Migrate cron, databaseEventTrigger, httpRoute triggers to serverless functions (#17488)

## Summary

Migrates trigger entities (`CronTriggerEntity`,
`DatabaseEventTriggerEntity`, `RouteTriggerEntity`) into
`ServerlessFunctionEntity` by storing trigger settings as JSONB columns
directly on the serverless function. This simplifies the architecture
since these relationships were effectively one-to-one.

## Changes

### Schema Changes
- Added three new nullable JSONB columns to `ServerlessFunctionEntity`:
  - `cronTriggerSettings` - stores cron pattern
- `databaseEventTriggerSettings` - stores event name and updated fields
filter
- `httpRouteTriggerSettings` - stores path, HTTP method, auth
requirements, and forwarded headers

### Core Logic Updates
- `CronTriggerCronJob` - now queries `ServerlessFunctionEntity` directly
instead of `CronTriggerEntity`
- `CallDatabaseEventTriggerJobsJob` - now queries
`ServerlessFunctionEntity` directly
- `RouteTriggerService` - now queries `ServerlessFunctionEntity`
directly
- `ApplicationSyncService` - extracts trigger settings from manifest and
writes to serverless function
This commit is contained in:
Charles Bochet
2026-01-27 20:54:09 +01:00
committed by GitHub
parent e1f92bd951
commit a4499d21bb
110 changed files with 439 additions and 5193 deletions
@@ -24,9 +24,7 @@ import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user
import { WebhookEntity } from 'src/engine/metadata-modules/webhook/entities/webhook.entity';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
import { CronTriggerEntity } from 'src/engine/metadata-modules/cron-trigger/entities/cron-trigger.entity';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { DatabaseEventTriggerEntity } from 'src/engine/metadata-modules/database-event-trigger/entities/database-event-trigger.entity';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
@@ -38,7 +36,6 @@ import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entiti
import { PermissionFlagEntity } from 'src/engine/metadata-modules/permission-flag/permission-flag.entity';
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { RouteTriggerEntity } from 'src/engine/metadata-modules/route-trigger/route-trigger.entity';
import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity';
import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity';
import { SearchFieldMetadataEntity } from 'src/engine/metadata-modules/search-field-metadata/search-field-metadata.entity';
@@ -81,9 +78,6 @@ const WORKSPACE_RELATED_ENTITIES: EntityTarget<ObjectLiteral>[] = [
ViewEntity,
IndexMetadataEntity,
PageLayoutTabEntity,
RouteTriggerEntity,
CronTriggerEntity,
DatabaseEventTriggerEntity,
// Level 2: Children that depend on core entities
FieldMetadataEntity,
@@ -0,0 +1,82 @@
import { type MigrationInterface, type QueryRunner } from 'typeorm';
export class MigrateServerlessTriggersToServerless1769532887284
implements MigrationInterface
{
name = 'MigrateServerlessTriggersToServerless1769532887284';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."serverlessFunction" ADD "cronTriggerSettings" jsonb`,
);
await queryRunner.query(
`ALTER TABLE "core"."serverlessFunction" ADD "databaseEventTriggerSettings" jsonb`,
);
await queryRunner.query(
`ALTER TABLE "core"."serverlessFunction" ADD "httpRouteTriggerSettings" jsonb`,
);
await queryRunner.query(
`DROP TABLE IF EXISTS "core"."cronTrigger" CASCADE`,
);
await queryRunner.query(
`DROP TABLE IF EXISTS "core"."databaseEventTrigger" CASCADE`,
);
await queryRunner.query(
`DROP TABLE IF EXISTS "core"."routeTrigger" CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."serverlessFunction" DROP COLUMN "httpRouteTriggerSettings"`,
);
await queryRunner.query(
`ALTER TABLE "core"."serverlessFunction" DROP COLUMN "databaseEventTriggerSettings"`,
);
await queryRunner.query(
`ALTER TABLE "core"."serverlessFunction" DROP COLUMN "cronTriggerSettings"`,
);
await queryRunner.query(`
CREATE TABLE "core"."cronTrigger" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"settings" jsonb NOT NULL,
"serverlessFunctionId" uuid NOT NULL,
"workspaceId" uuid NOT NULL,
"universalIdentifier" uuid NOT NULL,
"applicationId" uuid NOT NULL,
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
CONSTRAINT "PK_cronTrigger" PRIMARY KEY ("id")
)
`);
await queryRunner.query(`
CREATE TABLE "core"."databaseEventTrigger" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"settings" jsonb NOT NULL,
"serverlessFunctionId" uuid NOT NULL,
"workspaceId" uuid NOT NULL,
"universalIdentifier" uuid NOT NULL,
"applicationId" uuid NOT NULL,
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
CONSTRAINT "PK_databaseEventTrigger" PRIMARY KEY ("id")
)
`);
await queryRunner.query(`
CREATE TABLE "core"."routeTrigger" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"path" character varying NOT NULL,
"isAuthRequired" boolean NOT NULL DEFAULT true,
"httpMethod" character varying NOT NULL DEFAULT 'GET',
"forwardedRequestHeaders" jsonb NOT NULL DEFAULT '[]',
"serverlessFunctionId" uuid NOT NULL,
"workspaceId" uuid NOT NULL,
"universalIdentifier" uuid NOT NULL,
"applicationId" uuid NOT NULL,
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
CONSTRAINT "PK_routeTrigger" PRIMARY KEY ("id")
)
`);
}
}