From 94f7fbe276723b395400fcd93f34bd9daa4a34ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 10 May 2024 12:02:33 +0200 Subject: [PATCH 1/6] Initial setup --- .github/workflows/benchmark.yml | 47 +++++++++++ packages/nodes-base/package.json | 10 ++- packages/nodes-base/test/benchmark.ts | 29 +++++++ packages/nodes-base/test/nodes/Helpers.ts | 22 +++++- packages/nodes-base/tsconfig.benchmark.json | 9 +++ pnpm-lock.yaml | 86 +++++++++++++++++++-- 6 files changed, 189 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/benchmark.yml create mode 100644 packages/nodes-base/test/benchmark.ts create mode 100644 packages/nodes-base/tsconfig.benchmark.json diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000000000..5a9e9fa7a6d1c --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,47 @@ +name: Benchmark + +on: + pull_request: + paths: + - 'packages/cli/**' + - 'packages/core/**' + - 'packages/workflow/**' + - 'packages/nodes-base/**' + workflow_dispatch: + +jobs: + benchmark: + name: Benchmark + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4.1.1 + + - run: corepack enable + + - uses: actions/setup-node@v4.0.1 + with: + node-version: 18.x + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Build + if: ${{ inputs.cacheKey == '' }} + run: pnpm build:backend + + - name: Restore cached build artifacts + if: ${{ inputs.cacheKey != '' }} + uses: actions/cache/restore@v4.0.0 + with: + path: ./packages/**/dist + key: ${{ inputs.cacheKey }} + + - name: Build benchmarks + working-directory: packages/nodes-base + run: pnpm benchmark:build + + - name: Benchmark nodes-base + uses: CodSpeedHQ/action@v2 + with: + working-directory: packages/nodes-base + run: pnpm benchmark:run diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 410f982c738fb..edd8983fa594b 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -14,6 +14,8 @@ "url": "git+https://github.com/n8n-io/n8n.git" }, "scripts": { + "benchmark:build": "tsc -p tsconfig.benchmark.json > /dev/null; tsc-alias -p tsconfig.benchmark.json; pnpm build:metadata", + "benchmark:run": "NODE_ENV=benchmark node dist/test/benchmark.js", "clean": "rimraf dist .turbo", "dev": "pnpm watch", "typecheck": "tsc", @@ -808,6 +810,7 @@ ] }, "devDependencies": { + "@codspeed/tinybench-plugin": "^3.1.0", "@types/amqplib": "^0.10.1", "@types/aws4": "^1.5.1", "@types/basic-auth": "^1.1.3", @@ -815,8 +818,8 @@ "@types/cron": "~1.7.1", "@types/eventsource": "^1.1.2", "@types/express": "^4.17.21", - "@types/html-to-text": "^9.0.1", "@types/gm": "^1.25.0", + "@types/html-to-text": "^9.0.1", "@types/js-nacl": "^1.3.0", "@types/jsonwebtoken": "^9.0.6", "@types/lodash": "^4.14.195", @@ -835,7 +838,8 @@ "@types/uuid": "^8.3.2", "@types/xml2js": "^0.4.14", "eslint-plugin-n8n-nodes-base": "^1.16.0", - "n8n-core": "workspace:*" + "n8n-core": "workspace:*", + "tinybench": "^2.8.0" }, "dependencies": { "@kafkajs/confluent-schema-registry": "1.0.6", @@ -851,11 +855,11 @@ "csv-parse": "5.5.0", "currency-codes": "2.1.0", "eventsource": "2.0.2", - "html-to-text": "9.0.5", "fast-glob": "3.2.12", "fflate": "0.7.4", "get-system-fonts": "2.0.2", "gm": "1.25.0", + "html-to-text": "9.0.5", "iconv-lite": "0.6.3", "ics": "2.40.0", "isbot": "3.6.13", diff --git a/packages/nodes-base/test/benchmark.ts b/packages/nodes-base/test/benchmark.ts new file mode 100644 index 0000000000000..d90701704cb36 --- /dev/null +++ b/packages/nodes-base/test/benchmark.ts @@ -0,0 +1,29 @@ +import glob from 'fast-glob'; +import Bench from 'tinybench'; +import { withCodSpeed } from '@codspeed/tinybench-plugin'; +import { setup, workflowToTests as toTests } from './nodes/Helpers'; +import { executeWorkflow } from './nodes/ExecuteWorkflow'; + +async function main() { + const filePaths = await glob('nodes/**/*.workflow.json'); + + console.log(`Found ${filePaths.length} workflows to benchmark`); + + const tests = toTests(filePaths); + const nodeTypes = setup(tests); + const bench = withCodSpeed(new Bench({ time: 0, iterations: 1 })); // @TODO temp config + + // for (const test of tests) { + for (const test of tests.slice(0, 1)) { + bench.add(test.description, async () => { + await executeWorkflow(test, nodeTypes); + }); + } + + await bench.warmup(); + await bench.run(); + + console.table(bench.table()); +} + +void main(); diff --git a/packages/nodes-base/test/nodes/Helpers.ts b/packages/nodes-base/test/nodes/Helpers.ts index b5c6714280fbf..9718898573d05 100644 --- a/packages/nodes-base/test/nodes/Helpers.ts +++ b/packages/nodes-base/test/nodes/Helpers.ts @@ -38,7 +38,10 @@ import { executeWorkflow } from './ExecuteWorkflow'; import { FAKE_CREDENTIALS_DATA } from './FakeCredentialsMap'; -const baseDir = path.resolve(__dirname, '../..'); +const baseDir = path.resolve( + __dirname, + process.env.NODE_ENV === 'benchmark' ? '../../..' : '../..', +); const getFakeDecryptedCredentials = ( nodeCredentials: INodeCredentialsDetails, @@ -193,6 +196,10 @@ class NodeTypes implements INodeTypes { return this.nodeTypes[nodeType].type; } + getKnownTypes(): IDataObject { + return knownNodes; + } + addNode(nodeTypeName: string, nodeType: INodeType | IVersionedNodeType) { const loadedNode = { [nodeTypeName]: { @@ -255,7 +262,10 @@ export function setup(testData: WorkflowTestData[] | WorkflowTestData) { level: 'warning', }); } - const sourcePath = loadInfo.sourcePath.replace(/^dist\//, './').replace(/\.js$/, '.ts'); + const sourcePath = + process.env.NODE_ENV === 'benchmark' + ? loadInfo.sourcePath + : loadInfo.sourcePath.replace(/^dist\//, './').replace(/\.js$/, '.ts'); const nodeSourcePath = path.join(baseDir, sourcePath); const credential = new (require(nodeSourcePath)[loadInfo.className])() as ICredentialType; credentialTypes.addCredential(credentialName, credential); @@ -270,7 +280,10 @@ export function setup(testData: WorkflowTestData[] | WorkflowTestData) { if (!loadInfo) { throw new ApplicationError(`Unknown node type: ${nodeName}`, { level: 'warning' }); } - const sourcePath = loadInfo.sourcePath.replace(/^dist\//, './').replace(/\.js$/, '.ts'); + const sourcePath = + process.env.NODE_ENV === 'benchmark' + ? loadInfo.sourcePath + : loadInfo.sourcePath.replace(/^dist\//, './').replace(/\.js$/, '.ts'); const nodeSourcePath = path.join(baseDir, sourcePath); const node = new (require(nodeSourcePath)[loadInfo.className])() as INodeType; nodeTypes.addNode(nodeName, node); @@ -373,6 +386,9 @@ export const workflowToTests = (workflowFiles: string[]) => { ); } }); + + if (process.env.NODE_ENV === 'benchmark') workflowData.pinData = {}; + if (workflowData.pinData === undefined) { throw new ApplicationError('Workflow data does not contain pinData', { level: 'warning' }); } diff --git a/packages/nodes-base/tsconfig.benchmark.json b/packages/nodes-base/tsconfig.benchmark.json new file mode 100644 index 0000000000000..1bca6615904fd --- /dev/null +++ b/packages/nodes-base/tsconfig.benchmark.json @@ -0,0 +1,9 @@ +{ + "extends": ["./tsconfig.json", "../../tsconfig.build.json"], + "compilerOptions": { + "outDir": "dist/test", + "tsBuildInfoFile": "dist/benchmark.tsbuildinfo" + }, + "include": ["test/**/*.ts"], + "exclude": ["test/**/*.test.ts"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1226f304cf054..aa2e0d688c10d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -184,7 +184,7 @@ importers: dependencies: axios: specifier: 1.6.7 - version: 1.6.7(debug@3.2.7) + version: 1.6.7(debug@4.3.4) packages/@n8n/imap: dependencies: @@ -527,7 +527,7 @@ importers: version: 1.11.0 axios: specifier: 1.6.7 - version: 1.6.7(debug@3.2.7) + version: 1.6.7(debug@4.3.4) basic-auth: specifier: 2.0.1 version: 2.0.1 @@ -864,7 +864,7 @@ importers: version: 1.11.0 axios: specifier: 1.6.7 - version: 1.6.7(debug@3.2.7) + version: 1.6.7(debug@4.3.4) concat-stream: specifier: 2.0.0 version: 2.0.0 @@ -1121,7 +1121,7 @@ importers: version: 10.5.0(vue@3.4.21) axios: specifier: 1.6.7 - version: 1.6.7(debug@3.2.7) + version: 1.6.7(debug@4.3.4) chart.js: specifier: ^4.4.0 version: 4.4.0 @@ -1482,6 +1482,9 @@ importers: specifier: 0.6.2 version: 0.6.2 devDependencies: + '@codspeed/tinybench-plugin': + specifier: ^3.1.0 + version: 3.1.0(tinybench@2.8.0) '@types/amqplib': specifier: ^0.10.1 version: 0.10.1 @@ -1566,6 +1569,9 @@ importers: n8n-core: specifier: workspace:* version: link:../core + tinybench: + specifier: ^2.8.0 + version: 2.8.0 packages/workflow: dependencies: @@ -1583,7 +1589,7 @@ importers: version: 0.15.2 axios: specifier: 1.6.7 - version: 1.6.7(debug@3.2.7) + version: 1.6.7(debug@4.3.4) callsites: specifier: 3.1.0 version: 3.1.0 @@ -4710,6 +4716,29 @@ packages: w3c-keyname: 2.2.6 dev: false + /@codspeed/core@3.1.0: + resolution: {integrity: sha512-oYd7X46QhnRkgRbZkqAoX9i3Fwm17FpunK4Ee5RdrvRYR0Xr93ewH8/O5g6uyTPDOOqDEv1v2KRYtWhVgN+2VQ==} + dependencies: + axios: 1.6.7 + find-up: 6.3.0 + form-data: 4.0.0 + node-gyp-build: 4.7.0 + transitivePeerDependencies: + - debug + dev: true + + /@codspeed/tinybench-plugin@3.1.0(tinybench@2.8.0): + resolution: {integrity: sha512-yl0WzzUGIXkZzWaw7+2U+xGkuIal1Rs9hS09DtlDZGGAcGRoMMU5d2vyCS8nBrna4hrPQZ5Sx/hIKerO+lqWaw==} + peerDependencies: + tinybench: ^2.3.0 + dependencies: + '@codspeed/core': 3.1.0 + stack-trace: 1.0.0-pre2 + tinybench: 2.8.0 + transitivePeerDependencies: + - debug + dev: true + /@colors/colors@1.5.0: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -11483,12 +11512,11 @@ packages: /axios@1.6.7: resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} dependencies: - follow-redirects: 1.15.6(debug@3.2.7) + follow-redirects: 1.15.6(debug@4.3.4) form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - dev: false /axios@1.6.7(debug@3.2.7): resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} @@ -14901,6 +14929,14 @@ packages: path-exists: 4.0.0 dev: true + /find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + dev: true + /first-match@0.0.1: resolution: {integrity: sha512-VvKbnaxrC0polTFDC+teKPTdl2mn6B/KUW+WB3C9RzKDeNwbzfLdnUz3FxC+tnjvus6bI0jWrWicQyVIPdS37A==} dev: false @@ -18117,6 +18153,13 @@ packages: p-locate: 5.0.0 dev: true + /locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-locate: 6.0.0 + dev: true + /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} dev: false @@ -19222,7 +19265,6 @@ packages: /node-gyp-build@4.7.0: resolution: {integrity: sha512-PbZERfeFdrHQOOXiAKOY0VPbykZy90ndPKk0d+CFDegTKmWp1VgOTz2xACVbr1BjCWxrQp68CXtvNsveFhqDJg==} hasBin: true - dev: false /node-gyp@8.4.1: resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==} @@ -19750,6 +19792,13 @@ packages: dependencies: yocto-queue: 0.1.0 + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + /p-limit@5.0.0: resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} engines: {node: '>=18'} @@ -19777,6 +19826,13 @@ packages: p-limit: 3.1.0 dev: true + /p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-limit: 4.0.0 + dev: true + /p-map@4.0.0: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} @@ -19914,6 +19970,11 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + /path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -22420,6 +22481,11 @@ packages: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} dev: false + /stack-trace@1.0.0-pre2: + resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==} + engines: {node: '>=16'} + dev: true + /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -23062,6 +23128,10 @@ packages: resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==} dev: true + /tinybench@2.8.0: + resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} + dev: true + /tinypool@0.8.2: resolution: {integrity: sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==} engines: {node: '>=14.0.0'} From 98c89385732b52bedd5c7e95c2b62a24dfd460db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 10 May 2024 12:13:08 +0200 Subject: [PATCH 2/6] Remove temp restriction --- packages/nodes-base/test/benchmark.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/nodes-base/test/benchmark.ts b/packages/nodes-base/test/benchmark.ts index d90701704cb36..a721db52440f6 100644 --- a/packages/nodes-base/test/benchmark.ts +++ b/packages/nodes-base/test/benchmark.ts @@ -13,8 +13,7 @@ async function main() { const nodeTypes = setup(tests); const bench = withCodSpeed(new Bench({ time: 0, iterations: 1 })); // @TODO temp config - // for (const test of tests) { - for (const test of tests.slice(0, 1)) { + for (const test of tests) { bench.add(test.description, async () => { await executeWorkflow(test, nodeTypes); }); From 4c8f903f0cb454a720619cfd37eb238d9c2824bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 10 May 2024 12:37:04 +0200 Subject: [PATCH 3/6] Remove logging --- packages/nodes-base/test/benchmark.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/nodes-base/test/benchmark.ts b/packages/nodes-base/test/benchmark.ts index a721db52440f6..4ce7ad4848299 100644 --- a/packages/nodes-base/test/benchmark.ts +++ b/packages/nodes-base/test/benchmark.ts @@ -21,8 +21,6 @@ async function main() { await bench.warmup(); await bench.run(); - - console.table(bench.table()); } void main(); From 34efe10c976af64573f59e204094a4cefeb776b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 10 May 2024 12:57:06 +0200 Subject: [PATCH 4/6] Better naming --- .github/workflows/{benchmark.yml => benchmark-nodes-base.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{benchmark.yml => benchmark-nodes-base.yml} (97%) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark-nodes-base.yml similarity index 97% rename from .github/workflows/benchmark.yml rename to .github/workflows/benchmark-nodes-base.yml index 5a9e9fa7a6d1c..b1ae3182bd2c5 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark-nodes-base.yml @@ -1,4 +1,4 @@ -name: Benchmark +name: Benchmark nodes-base on: pull_request: From f581e40fe41fe66b0bd767dcbf7ab1b0b3f6195d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 10 May 2024 13:42:31 +0200 Subject: [PATCH 5/6] Remove cli path from GH action trigger --- .github/workflows/benchmark-nodes-base.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/benchmark-nodes-base.yml b/.github/workflows/benchmark-nodes-base.yml index b1ae3182bd2c5..6c6fbc6cda388 100644 --- a/.github/workflows/benchmark-nodes-base.yml +++ b/.github/workflows/benchmark-nodes-base.yml @@ -3,7 +3,6 @@ name: Benchmark nodes-base on: pull_request: paths: - - 'packages/cli/**' - 'packages/core/**' - 'packages/workflow/**' - 'packages/nodes-base/**' From 4ccef058a6a5e753a6745f6509569564d8b67272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 10 May 2024 19:12:14 +0200 Subject: [PATCH 6/6] perf: Reduce variance in `nodes-base` benchmarks (#9363) --- packages/nodes-base/test/benchmark.ts | 14 ++++- .../nodes-base/test/nodes/ExecuteWorkflow.ts | 51 ++++++++++++++++--- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/packages/nodes-base/test/benchmark.ts b/packages/nodes-base/test/benchmark.ts index 4ce7ad4848299..3c68be6f8bdae 100644 --- a/packages/nodes-base/test/benchmark.ts +++ b/packages/nodes-base/test/benchmark.ts @@ -2,7 +2,7 @@ import glob from 'fast-glob'; import Bench from 'tinybench'; import { withCodSpeed } from '@codspeed/tinybench-plugin'; import { setup, workflowToTests as toTests } from './nodes/Helpers'; -import { executeWorkflow } from './nodes/ExecuteWorkflow'; +import { performExecution, setupExecution } from './nodes/ExecuteWorkflow'; async function main() { const filePaths = await glob('nodes/**/*.workflow.json'); @@ -14,8 +14,18 @@ async function main() { const bench = withCodSpeed(new Bench({ time: 0, iterations: 1 })); // @TODO temp config for (const test of tests) { + const { waitPromise, additionalData, executionMode, workflowInstance, nodeExecutionOrder } = + await setupExecution(test, nodeTypes); + bench.add(test.description, async () => { - await executeWorkflow(test, nodeTypes); + await performExecution( + waitPromise, + additionalData, + executionMode, + test, + workflowInstance, + nodeExecutionOrder, + ); }); } diff --git a/packages/nodes-base/test/nodes/ExecuteWorkflow.ts b/packages/nodes-base/test/nodes/ExecuteWorkflow.ts index 528eca40a901b..c33dd575df679 100644 --- a/packages/nodes-base/test/nodes/ExecuteWorkflow.ts +++ b/packages/nodes-base/test/nodes/ExecuteWorkflow.ts @@ -1,11 +1,18 @@ import nock from 'nock'; import { WorkflowExecute } from 'n8n-core'; -import type { INodeTypes, IRun, IRunExecutionData } from 'n8n-workflow'; +import type { + IDeferredPromise, + INodeTypes, + IRun, + IRunExecutionData, + IWorkflowExecuteAdditionalData, + WorkflowExecuteMode, +} from 'n8n-workflow'; import { createDeferredPromise, Workflow } from 'n8n-workflow'; import * as Helpers from './Helpers'; import type { WorkflowTestData } from './types'; -export async function executeWorkflow(testData: WorkflowTestData, nodeTypes: INodeTypes) { +export async function setupExecution(testData: WorkflowTestData, nodeTypes: INodeTypes) { if (testData.nock) { const { baseUrl, mocks } = testData.nock; const agent = nock(baseUrl); @@ -30,7 +37,24 @@ export async function executeWorkflow(testData: WorkflowTestData, nodeTypes: INo testData, ); - let executionData: IRun; + return { + waitPromise, + additionalData, + executionMode, + testData, + workflowInstance, + nodeExecutionOrder, + }; +} + +export async function performExecution( + waitPromise: IDeferredPromise, + additionalData: IWorkflowExecuteAdditionalData, + executionMode: WorkflowExecuteMode, + testData: WorkflowTestData, + workflowInstance: Workflow, + nodeExecutionOrder: string[], +) { const runExecutionData: IRunExecutionData = { resultData: { runData: {}, @@ -50,9 +74,24 @@ export async function executeWorkflow(testData: WorkflowTestData, nodeTypes: INo ], }, }; - const workflowExecute = new WorkflowExecute(additionalData, executionMode, runExecutionData); - executionData = await workflowExecute.processRunExecutionData(workflowInstance); + const workflowExecute = new WorkflowExecute(additionalData, executionMode, runExecutionData); + const finalExecutionData = await workflowExecute.processRunExecutionData(workflowInstance); const result = await waitPromise.promise(); - return { executionData, result, nodeExecutionOrder }; + + return { executionData: finalExecutionData, result, nodeExecutionOrder }; +} + +export async function executeWorkflow(testData: WorkflowTestData, nodeTypes: INodeTypes) { + const { waitPromise, additionalData, executionMode, workflowInstance, nodeExecutionOrder } = + await setupExecution(testData, nodeTypes); + + return await performExecution( + waitPromise, + additionalData, + executionMode, + testData, + workflowInstance, + nodeExecutionOrder, + ); }