2024-08-29 22:46:55 -07:00
#!/usr/bin/env zx
/ * *
* This script runs the benchmarks for the given n8n setup .
* /
// @ts-check
import path from 'path' ;
import { $ , argv , fs } from 'zx' ;
2024-09-12 06:06:43 -07:00
import { DockerComposeClient } from './clients/docker-compose-client.mjs' ;
2024-09-09 23:25:41 -07:00
import { flagsObjectToCliArgs } from './utils/flags.mjs' ;
2024-08-29 22:46:55 -07:00
const paths = {
2024-09-12 06:06:43 -07:00
n8nSetupsDir : path . join ( _ _dirname , 'n8n-setups' ) ,
mockApiDataPath : path . join ( _ _dirname , 'mock-api' ) ,
2024-08-29 22:46:55 -07:00
} ;
2024-09-08 23:07:32 -07:00
const N8N _ENCRYPTION _KEY = 'very-secret-encryption-key' ;
2024-08-29 22:46:55 -07:00
async function main ( ) {
const [ n8nSetupToUse ] = argv . _ ;
validateN8nSetup ( n8nSetupToUse ) ;
const composeFilePath = path . join ( paths . n8nSetupsDir , n8nSetupToUse ) ;
2024-09-02 04:58:24 -07:00
const setupScriptPath = path . join ( paths . n8nSetupsDir , n8nSetupToUse , 'setup.mjs' ) ;
2024-08-29 22:46:55 -07:00
const n8nTag = argv . n8nDockerTag || process . env . N8N _DOCKER _TAG || 'latest' ;
const benchmarkTag = argv . benchmarkDockerTag || process . env . BENCHMARK _DOCKER _TAG || 'latest' ;
const k6ApiToken = argv . k6ApiToken || process . env . K6 _API _TOKEN || undefined ;
2024-09-10 07:41:33 -07:00
const resultWebhookUrl =
argv . resultWebhookUrl || process . env . BENCHMARK _RESULT _WEBHOOK _URL || undefined ;
const resultWebhookAuthHeader =
argv . resultWebhookAuthHeader || process . env . BENCHMARK _RESULT _WEBHOOK _AUTH _HEADER || undefined ;
2024-08-29 23:41:50 -07:00
const baseRunDir = argv . runDir || process . env . RUN _DIR || '/n8n' ;
2024-09-08 23:07:32 -07:00
const n8nLicenseCert = argv . n8nLicenseCert || process . env . N8N _LICENSE _CERT || undefined ;
const n8nLicenseActivationKey = process . env . N8N _LICENSE _ACTIVATION _KEY || '' ;
const n8nLicenseTenantId = argv . n8nLicenseTenantId || process . env . N8N _LICENSE _TENANT _ID || '' ;
2024-09-10 07:41:33 -07:00
const envTag = argv . env || 'local' ;
2024-09-09 23:25:41 -07:00
const vus = argv . vus ;
const duration = argv . duration ;
2024-08-29 22:46:55 -07:00
2024-09-11 01:12:03 -07:00
const hasN8nLicense = ! ! n8nLicenseCert || ! ! n8nLicenseActivationKey ;
2024-09-12 03:02:56 -07:00
if ( n8nSetupToUse === 'scaling-multi-main' && ! hasN8nLicense ) {
2024-09-11 01:12:03 -07:00
console . error (
2024-09-12 03:02:56 -07:00
'n8n license is required to run the multi-main scaling setup. Please provide N8N_LICENSE_CERT or N8N_LICENSE_ACTIVATION_KEY (and N8N_LICENSE_TENANT_ID if needed)' ,
2024-09-11 01:12:03 -07:00
) ;
process . exit ( 1 ) ;
}
2024-08-29 23:41:50 -07:00
if ( ! fs . existsSync ( baseRunDir ) ) {
2024-08-29 22:46:55 -07:00
console . error (
2024-08-29 23:41:50 -07:00
` The run directory " ${ baseRunDir } " does not exist. Please specify a valid directory using --runDir ` ,
2024-08-29 22:46:55 -07:00
) ;
process . exit ( 1 ) ;
}
2024-08-29 23:41:50 -07:00
const runDir = path . join ( baseRunDir , n8nSetupToUse ) ;
fs . emptyDirSync ( runDir ) ;
2024-08-29 22:46:55 -07:00
const dockerComposeClient = new DockerComposeClient ( {
$ : $ ( {
cwd : composeFilePath ,
verbose : true ,
env : {
2024-09-08 23:07:32 -07:00
PATH : process . env . PATH ,
2024-08-29 22:46:55 -07:00
N8N _VERSION : n8nTag ,
2024-09-08 23:07:32 -07:00
N8N _LICENSE _CERT : n8nLicenseCert ,
N8N _LICENSE _ACTIVATION _KEY : n8nLicenseActivationKey ,
N8N _LICENSE _TENANT _ID : n8nLicenseTenantId ,
N8N _ENCRYPTION _KEY ,
2024-08-29 22:46:55 -07:00
BENCHMARK _VERSION : benchmarkTag ,
K6 _API _TOKEN : k6ApiToken ,
2024-09-10 07:41:33 -07:00
BENCHMARK _RESULT _WEBHOOK _URL : resultWebhookUrl ,
BENCHMARK _RESULT _WEBHOOK _AUTH _HEADER : resultWebhookAuthHeader ,
2024-08-29 22:46:55 -07:00
RUN _DIR : runDir ,
2024-09-04 23:42:58 -07:00
MOCK _API _DATA _PATH : paths . mockApiDataPath ,
2024-08-29 22:46:55 -07:00
} ,
} ) ,
} ) ;
2024-09-02 04:58:24 -07:00
// Run the setup script if it exists
if ( fs . existsSync ( setupScriptPath ) ) {
const setupScript = await import ( setupScriptPath ) ;
await setupScript . setup ( { runDir } ) ;
}
2024-08-29 22:46:55 -07:00
try {
2024-08-29 23:41:50 -07:00
await dockerComposeClient . $ ( 'up' , '-d' , '--remove-orphans' , 'n8n' ) ;
2024-08-29 22:46:55 -07:00
2024-09-09 23:25:41 -07:00
const tags = Object . entries ( {
2024-09-10 07:41:33 -07:00
Env : envTag ,
2024-09-09 23:25:41 -07:00
N8nVersion : n8nTag ,
N8nSetup : n8nSetupToUse ,
} )
. map ( ( [ key , value ] ) => ` ${ key } = ${ value } ` )
. join ( ',' ) ;
const cliArgs = flagsObjectToCliArgs ( {
scenarioNamePrefix : n8nSetupToUse ,
vus ,
duration ,
tags ,
} ) ;
await dockerComposeClient . $ ( 'run' , 'benchmark' , 'run' , ... cliArgs ) ;
2024-08-29 22:46:55 -07:00
} catch ( error ) {
console . error ( 'An error occurred while running the benchmarks:' ) ;
2024-09-08 23:07:32 -07:00
console . error ( error . message ) ;
console . error ( '' ) ;
await printContainerStatus ( dockerComposeClient ) ;
2024-08-29 22:46:55 -07:00
console . error ( '' ) ;
2024-09-08 23:07:32 -07:00
await dumpLogs ( dockerComposeClient ) ;
2024-08-29 22:46:55 -07:00
} finally {
await dockerComposeClient . $ ( 'down' ) ;
}
}
2024-09-08 23:07:32 -07:00
async function printContainerStatus ( dockerComposeClient ) {
console . error ( 'Container statuses:' ) ;
await dockerComposeClient . $ ( 'ps' , '-a' ) ;
}
async function dumpLogs ( dockerComposeClient ) {
console . error ( 'Container logs:' ) ;
await dockerComposeClient . $ ( 'logs' ) ;
2024-08-29 22:46:55 -07:00
}
function printUsage ( ) {
const availableSetups = getAllN8nSetups ( ) ;
console . log ( 'Usage: zx runForN8nSetup.mjs --runDir /path/for/n8n/data <n8n setup to use>' ) ;
console . log ( ` eg: zx runForN8nSetup.mjs --runDir /path/for/n8n/data ${ availableSetups [ 0 ] } ` ) ;
console . log ( '' ) ;
console . log ( 'Flags:' ) ;
console . log (
' --runDir <path> Directory to share with the n8n container for storing data. Default is /n8n' ,
) ;
console . log ( ' --n8nDockerTag <tag> Docker tag for n8n image. Default is latest' ) ;
console . log (
' --benchmarkDockerTag <tag> Docker tag for benchmark cli image. Default is latest' ,
) ;
console . log ( ' --k6ApiToken <token> K6 API token to upload the results' ) ;
console . log ( '' ) ;
console . log ( 'Available setups:' ) ;
console . log ( availableSetups . join ( ', ' ) ) ;
}
/ * *
* @ returns { string [ ] }
* /
function getAllN8nSetups ( ) {
return fs . readdirSync ( paths . n8nSetupsDir ) ;
}
function validateN8nSetup ( givenSetup ) {
const availableSetups = getAllN8nSetups ( ) ;
if ( ! availableSetups . includes ( givenSetup ) ) {
printUsage ( ) ;
process . exit ( 1 ) ;
}
}
main ( ) ;