mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-03 18:27:09 +02:00
feat(core): Add workflow publication outbox database table (no-changelog) (#26936)
Co-authored-by: Tomi Turtiainen <10324676+tomi@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6edd4cea36
commit
4cdd079385
|
|
@ -42,6 +42,8 @@ import { WebhookEntity } from './webhook-entity';
|
|||
import { WorkflowDependency } from './workflow-dependency-entity';
|
||||
import { WorkflowEntity } from './workflow-entity';
|
||||
import { WorkflowHistory } from './workflow-history';
|
||||
import { WorkflowPublicationOutbox } from './workflow-publication-outbox';
|
||||
import type { WorkflowPublicationOutboxStatus } from './workflow-publication-outbox';
|
||||
import { WorkflowPublishHistory } from './workflow-publish-history';
|
||||
import { WorkflowPublishedVersion } from './workflow-published-version';
|
||||
import { WorkflowStatistics } from './workflow-statistics';
|
||||
|
|
@ -83,6 +85,8 @@ export {
|
|||
FolderTagMapping,
|
||||
AuthProviderSyncHistory,
|
||||
WorkflowHistory,
|
||||
WorkflowPublicationOutbox,
|
||||
type WorkflowPublicationOutboxStatus,
|
||||
WorkflowPublishedVersion,
|
||||
WorkflowPublishHistory,
|
||||
ExecutionData,
|
||||
|
|
@ -129,6 +133,7 @@ export const entities = {
|
|||
FolderTagMapping,
|
||||
AuthProviderSyncHistory,
|
||||
WorkflowHistory,
|
||||
WorkflowPublicationOutbox,
|
||||
WorkflowPublishedVersion,
|
||||
WorkflowPublishHistory,
|
||||
ExecutionData,
|
||||
|
|
|
|||
28
packages/@n8n/db/src/entities/workflow-publication-outbox.ts
Normal file
28
packages/@n8n/db/src/entities/workflow-publication-outbox.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { Column, Entity, PrimaryGeneratedColumn } from '@n8n/typeorm';
|
||||
|
||||
import { WithTimestamps } from './abstract-entity';
|
||||
|
||||
export type WorkflowPublicationOutboxStatus =
|
||||
| 'pending'
|
||||
| 'in_progress'
|
||||
| 'completed'
|
||||
| 'partial_success'
|
||||
| 'failed';
|
||||
|
||||
@Entity({ name: 'workflow_publication_outbox' })
|
||||
export class WorkflowPublicationOutbox extends WithTimestamps {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ type: 'varchar', length: 36 })
|
||||
workflowId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 36 })
|
||||
publishedVersionId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 20 })
|
||||
status: WorkflowPublicationOutboxStatus;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
errorMessage: string | null;
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import type { MigrationContext, ReversibleMigration } from '../migration-types';
|
||||
|
||||
/**
|
||||
* Creates the workflow_publication_outbox table for the transactional outbox
|
||||
* pattern. Each row represents a pending (or in-progress / completed)
|
||||
* publication request that the outbox consumer will process asynchronously.
|
||||
*/
|
||||
export class CreateWorkflowPublicationOutboxTable1784000000020 implements ReversibleMigration {
|
||||
async up({ schemaBuilder: { createTable, column } }: MigrationContext) {
|
||||
await createTable('workflow_publication_outbox').withColumns(
|
||||
column('id').int.primary.autoGenerate2,
|
||||
// No foreign keys on workflowId or publishedVersionId: this is a
|
||||
// transient queue table. If a workflow or history version is
|
||||
// deleted while a publication is in-flight, the outbox consumer
|
||||
// will encounter the orphaned record and fail gracefully. Using
|
||||
// FKs would either silently delete the record (CASCADE) or block
|
||||
// workflow deletion (RESTRICT), neither of which is desirable.
|
||||
column('workflowId')
|
||||
.varchar(36)
|
||||
.notNull.comment('References workflow_entity.id.'),
|
||||
column('publishedVersionId')
|
||||
.varchar(36)
|
||||
.notNull.comment('References workflow_history.versionId.'),
|
||||
column('status')
|
||||
.varchar(20)
|
||||
.notNull.withEnumCheck([
|
||||
'pending',
|
||||
'in_progress',
|
||||
'completed',
|
||||
'partial_success',
|
||||
'failed',
|
||||
]),
|
||||
column('errorMessage').text.comment(
|
||||
'Error details for surfacing failed publications to the user.',
|
||||
),
|
||||
).withTimestamps;
|
||||
}
|
||||
|
||||
async down({ schemaBuilder: { dropTable } }: MigrationContext) {
|
||||
await dropTable('workflow_publication_outbox');
|
||||
}
|
||||
}
|
||||
|
|
@ -195,6 +195,7 @@ import { UseSlugAsPrimaryKeyInMcpRegistryServer1784000000016 } from '../common/1
|
|||
import { AddLastUsedAtToApiKey1784000000017 } from '../common/1784000000017-AddLastUsedAtToApiKey';
|
||||
import { CreateAgentFilesTable1784000000018 } from '../common/1784000000018-CreateAgentFilesTable';
|
||||
import { AddCustomTelemetryTagsToProject1784000000019 } from '../common/1784000000019-AddCustomTelemetryTagsToProject';
|
||||
import { CreateWorkflowPublicationOutboxTable1784000000020 } from '../common/1784000000020-CreateWorkflowPublicationOutboxTable';
|
||||
import type { Migration } from '../migration-types';
|
||||
|
||||
export const postgresMigrations: Migration[] = [
|
||||
|
|
@ -395,4 +396,5 @@ export const postgresMigrations: Migration[] = [
|
|||
AddLastUsedAtToApiKey1784000000017,
|
||||
CreateAgentFilesTable1784000000018,
|
||||
AddCustomTelemetryTagsToProject1784000000019,
|
||||
CreateWorkflowPublicationOutboxTable1784000000020,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ import { UseSlugAsPrimaryKeyInMcpRegistryServer1784000000016 } from '../common/1
|
|||
import { AddLastUsedAtToApiKey1784000000017 } from '../common/1784000000017-AddLastUsedAtToApiKey';
|
||||
import { CreateAgentFilesTable1784000000018 } from '../common/1784000000018-CreateAgentFilesTable';
|
||||
import { AddCustomTelemetryTagsToProject1784000000019 } from '../common/1784000000019-AddCustomTelemetryTagsToProject';
|
||||
import { CreateWorkflowPublicationOutboxTable1784000000020 } from '../common/1784000000020-CreateWorkflowPublicationOutboxTable';
|
||||
import type { Migration } from '../migration-types';
|
||||
|
||||
const sqliteMigrations: Migration[] = [
|
||||
|
|
@ -381,6 +382,7 @@ const sqliteMigrations: Migration[] = [
|
|||
AddLastUsedAtToApiKey1784000000017,
|
||||
CreateAgentFilesTable1784000000018,
|
||||
AddCustomTelemetryTagsToProject1784000000019,
|
||||
CreateWorkflowPublicationOutboxTable1784000000020,
|
||||
];
|
||||
|
||||
export { sqliteMigrations };
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export { WorkflowTagMappingRepository } from './workflow-tag-mapping.repository'
|
|||
export { SharedWorkflowRepository } from './shared-workflow.repository';
|
||||
export { SharedCredentialsRepository } from './shared-credentials.repository';
|
||||
export { WorkflowRepository } from './workflow.repository';
|
||||
export { WorkflowPublicationOutboxRepository } from './workflow-publication-outbox.repository';
|
||||
export { WorkflowPublishedVersionRepository } from './workflow-published-version.repository';
|
||||
export { WorkflowPublishHistoryRepository } from './workflow-publish-history.repository';
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
import { Service } from '@n8n/di';
|
||||
import { DataSource, Repository } from '@n8n/typeorm';
|
||||
|
||||
import { WorkflowPublicationOutbox } from '../entities/workflow-publication-outbox';
|
||||
|
||||
@Service()
|
||||
export class WorkflowPublicationOutboxRepository extends Repository<WorkflowPublicationOutbox> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(WorkflowPublicationOutbox, dataSource.manager);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user