From 156cb1b52f45020e5e341c749197a618778c156d Mon Sep 17 00:00:00 2001 From: martmull Date: Wed, 9 Jul 2025 14:48:44 +0200 Subject: [PATCH] 13058 workflow with code fail to run (#13118) - update publishOneServerlessFunction so it does not break the workflow if failing - update upgrade documentation to update `docker-compose.yml` when mutated Fixes https://github.com/twentyhq/twenty/issues/13058 --- .../serverless-function.resolver.ts | 2 +- .../serverless-function.service.ts | 35 ++++++++++++++----- .../workflow-statuses-update.job.spec.ts | 7 ++-- .../jobs/workflow-statuses-update.job.ts | 28 ++------------- .../developers/self-hosting/upgrade-guide.mdx | 5 +++ 5 files changed, 41 insertions(+), 36 deletions(-) diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.resolver.ts index 353aa99b9..15848da86 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.resolver.ts @@ -163,7 +163,7 @@ export class ServerlessFunctionResolver { try { const { id } = input; - return await this.serverlessFunctionService.publishOneServerlessFunction( + return await this.serverlessFunctionService.publishOneServerlessFunctionOrFail( id, workspaceId, ); diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts index bef901eee..4dd0b604b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts @@ -30,6 +30,10 @@ import { ServerlessFunctionException, ServerlessFunctionExceptionCode, } from 'src/engine/metadata-modules/serverless-function/serverless-function.exception'; +import { + WorkflowVersionStepException, + WorkflowVersionStepExceptionCode, +} from 'src/modules/workflow/common/exceptions/workflow-version-step.exception'; @Injectable() export class ServerlessFunctionService { @@ -137,7 +141,7 @@ export class ServerlessFunctionService { return resultServerlessFunction; } - async publishOneServerlessFunction(id: string, workspaceId: string) { + async publishOneServerlessFunctionOrFail(id: string, workspaceId: string) { const existingServerlessFunction = await this.serverlessFunctionRepository.findOneOrFail({ where: { @@ -159,10 +163,7 @@ export class ServerlessFunctionService { ); if (deepEqual(latestCode, draftCode)) { - throw new ServerlessFunctionException( - 'Cannot publish a new version when code has not changed', - ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_CODE_UNCHANGED, - ); + return existingServerlessFunction; } } @@ -174,6 +175,7 @@ export class ServerlessFunctionService { serverlessFunction: existingServerlessFunction, version: 'draft', }); + const newFolderPath = getServerlessFolder({ serverlessFunction: existingServerlessFunction, version: newVersion, @@ -197,9 +199,26 @@ export class ServerlessFunctionService { }, ); - return this.serverlessFunctionRepository.findOneBy({ - id: existingServerlessFunction.id, - }); + const publishedServerlessFunction = + await this.serverlessFunctionRepository.findOneOrFail({ + where: { + id, + workspaceId, + }, + }); + + // This check should never be thrown, but we encounter some issue with + // publishing serverless function in self hosted instances + // See https://github.com/twentyhq/twenty/issues/13058 + // TODO: remove this check when issue solved + if (!isDefined(publishedServerlessFunction.latestVersion)) { + throw new WorkflowVersionStepException( + `Fail to publish serverlessFunction ${publishedServerlessFunction.id}.Received latest version ${publishedServerlessFunction.latestVersion}`, + WorkflowVersionStepExceptionCode.FAILURE, + ); + } + + return publishedServerlessFunction; } async deleteOneServerlessFunction({ diff --git a/packages/twenty-server/src/modules/workflow/workflow-status/jobs/__tests__/workflow-statuses-update.job.spec.ts b/packages/twenty-server/src/modules/workflow/workflow-status/jobs/__tests__/workflow-statuses-update.job.spec.ts index 1b5ae934e..767b73066 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-status/jobs/__tests__/workflow-statuses-update.job.spec.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-status/jobs/__tests__/workflow-statuses-update.job.spec.ts @@ -50,7 +50,7 @@ describe('WorkflowStatusesUpdate', () => { }; const mockServerlessFunctionService = { - publishOneServerlessFunction: jest.fn(), + publishOneServerlessFunctionOrFail: jest.fn(), findOneOrFail: jest.fn(), }; @@ -256,6 +256,9 @@ describe('WorkflowStatusesUpdate', () => { mockServerlessFunctionService.findOneOrFail.mockResolvedValue( mockServerlessFunction, ); + mockServerlessFunctionService.publishOneServerlessFunctionOrFail.mockResolvedValue( + mockServerlessFunction, + ); await job.handle(event); @@ -264,7 +267,7 @@ describe('WorkflowStatusesUpdate', () => { mockWorkflowVersionRepository.findOneOrFail, ).toHaveBeenCalledTimes(1); expect( - mockServerlessFunctionService.publishOneServerlessFunction, + mockServerlessFunctionService.publishOneServerlessFunctionOrFail, ).toHaveBeenCalledWith('serverless-1', '1'); expect(mockWorkflowVersionRepository.update).toHaveBeenCalledWith('1', { steps: [ diff --git a/packages/twenty-server/src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job.ts b/packages/twenty-server/src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job.ts index 44a1b55a7..9e89675be 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job.ts @@ -11,7 +11,6 @@ import { Processor } from 'src/engine/core-modules/message-queue/decorators/proc import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity'; -import { ServerlessFunctionExceptionCode } from 'src/engine/metadata-modules/serverless-function/serverless-function.exception'; import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; @@ -198,33 +197,11 @@ export class WorkflowStatusesUpdateJob { const newStep = { ...step }; if (step.type === WorkflowActionType.CODE) { - try { - await this.serverlessFunctionService.publishOneServerlessFunction( + const serverlessFunction = + await this.serverlessFunctionService.publishOneServerlessFunctionOrFail( step.settings.input.serverlessFunctionId, workspaceId, ); - } catch (e) { - // publishOneServerlessFunction throws if no change have been - // applied between draft and lastPublished version. - // If no change have been applied, we just use the same - // serverless function version - if ( - e.code !== - ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_CODE_UNCHANGED - ) { - this.logger.error( - `Error while publishing serverless function '${step.settings.input.serverlessFunctionId}': ${e}`, - ); - } - } - - const serverlessFunction = - await this.serverlessFunctionRepository.findOneOrFail({ - where: { - id: step.settings.input.serverlessFunctionId, - workspaceId, - }, - }); const newStepSettings = { ...step.settings }; @@ -233,6 +210,7 @@ export class WorkflowStatusesUpdateJob { newStep.settings = newStepSettings; } + newSteps.push(newStep); } diff --git a/packages/twenty-website/src/content/developers/self-hosting/upgrade-guide.mdx b/packages/twenty-website/src/content/developers/self-hosting/upgrade-guide.mdx index 790d9fa5a..3a3422a4c 100644 --- a/packages/twenty-website/src/content/developers/self-hosting/upgrade-guide.mdx +++ b/packages/twenty-website/src/content/developers/self-hosting/upgrade-guide.mdx @@ -119,6 +119,11 @@ yarn database:migrate:prod yarn command:prod upgrade ``` +#### Docker-compose.yml mutation + +This version includes a `docker-compose.yml` mutation to give `worker` service access to the `server-local-data` volume. +Please update your local `docker-compose.yml` with [v0.50.0 docker-compose.yml](https://github.com/twentyhq/twenty/blob/v0.50.0/packages/twenty-docker/docker-compose.yml) + ### v0.43.0 to v0.44.0 Upgrade your Twenty instance to use v0.44.0 image