feat(core): Enforce one pending outbox row per workflow (no-changelog) (#31497)

This commit is contained in:
mfsiega 2026-06-01 16:42:22 +02:00 committed by GitHub
parent ce886a21a3
commit f7d474965f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 16 additions and 2 deletions

View File

@ -1,4 +1,4 @@
import { Column, Entity, PrimaryGeneratedColumn } from '@n8n/typeorm';
import { Column, Entity, Index, PrimaryGeneratedColumn } from '@n8n/typeorm';
import { WithTimestamps } from './abstract-entity';
@ -10,6 +10,10 @@ export type WorkflowPublicationOutboxStatus =
| 'failed';
@Entity({ name: 'workflow_publication_outbox' })
@Index('IDX_workflow_publication_outbox_pending_workflow', ['workflowId'], {
unique: true,
where: "status = 'pending'",
})
export class WorkflowPublicationOutbox extends WithTimestamps {
@PrimaryGeneratedColumn()
id: number;

View File

@ -6,7 +6,7 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types';
* publication request that the outbox consumer will process asynchronously.
*/
export class CreateWorkflowPublicationOutboxTable1784000000020 implements ReversibleMigration {
async up({ schemaBuilder: { createTable, column } }: MigrationContext) {
async up({ schemaBuilder: { createTable, createIndex, column } }: MigrationContext) {
await createTable('workflow_publication_outbox').withColumns(
column('id').int.primary.autoGenerate2,
// No foreign keys on workflowId or publishedVersionId: this is a
@ -34,6 +34,16 @@ export class CreateWorkflowPublicationOutboxTable1784000000020 implements Revers
'Error details for surfacing failed publications to the user.',
),
).withTimestamps;
// At most one pending record per workflow: enqueueing a newer version
// while one is still pending supersedes the older publishedVersionId.
await createIndex(
'workflow_publication_outbox',
['workflowId'],
true,
'IDX_workflow_publication_outbox_pending_workflow',
"status = 'pending'",
);
}
async down({ schemaBuilder: { dropTable } }: MigrationContext) {