mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
refactor(core): Port cache config (no-changelog) (#10286)
This commit is contained in:
parent
aa0a470dce
commit
acbae928f2
36
packages/@n8n/config/src/configs/cache.ts
Normal file
36
packages/@n8n/config/src/configs/cache.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
|
@Config
|
||||||
|
class MemoryConfig {
|
||||||
|
/** Max size of memory cache in bytes */
|
||||||
|
@Env('N8N_CACHE_MEMORY_MAX_SIZE')
|
||||||
|
maxSize = 3 * 1024 * 1024; // 3 MiB
|
||||||
|
|
||||||
|
/** Time to live (in milliseconds) for data cached in memory. */
|
||||||
|
@Env('N8N_CACHE_MEMORY_TTL')
|
||||||
|
ttl = 3600 * 1000; // 1 hour
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config
|
||||||
|
class RedisConfig {
|
||||||
|
/** Prefix for cache keys in Redis. */
|
||||||
|
@Env('N8N_CACHE_REDIS_KEY_PREFIX')
|
||||||
|
prefix = 'redis';
|
||||||
|
|
||||||
|
/** Time to live (in milliseconds) for data cached in Redis. 0 for no TTL. */
|
||||||
|
@Env('N8N_CACHE_REDIS_TTL')
|
||||||
|
ttl = 3600 * 1000; // 1 hour
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config
|
||||||
|
export class CacheConfig {
|
||||||
|
/** Backend to use for caching. */
|
||||||
|
@Env('N8N_CACHE_BACKEND')
|
||||||
|
backend: 'memory' | 'redis' | 'auto' = 'auto';
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
memory: MemoryConfig;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
redis: RedisConfig;
|
||||||
|
}
|
|
@ -7,19 +7,19 @@ class CredentialsOverwrite {
|
||||||
* Format: { CREDENTIAL_NAME: { PARAMETER: VALUE }}
|
* Format: { CREDENTIAL_NAME: { PARAMETER: VALUE }}
|
||||||
*/
|
*/
|
||||||
@Env('CREDENTIALS_OVERWRITE_DATA')
|
@Env('CREDENTIALS_OVERWRITE_DATA')
|
||||||
readonly data: string = '{}';
|
data = '{}';
|
||||||
|
|
||||||
/** Internal API endpoint to fetch overwritten credential types from. */
|
/** Internal API endpoint to fetch overwritten credential types from. */
|
||||||
@Env('CREDENTIALS_OVERWRITE_ENDPOINT')
|
@Env('CREDENTIALS_OVERWRITE_ENDPOINT')
|
||||||
readonly endpoint: string = '';
|
endpoint = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class CredentialsConfig {
|
export class CredentialsConfig {
|
||||||
/** Default name for credentials */
|
/** Default name for credentials */
|
||||||
@Env('CREDENTIALS_DEFAULT_NAME')
|
@Env('CREDENTIALS_DEFAULT_NAME')
|
||||||
readonly defaultName: string = 'My credentials';
|
defaultName = 'My credentials';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly overwrite: CredentialsOverwrite;
|
overwrite: CredentialsOverwrite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,19 @@ import { Config, Env, Nested } from '../decorators';
|
||||||
class LoggingConfig {
|
class LoggingConfig {
|
||||||
/** Whether database logging is enabled. */
|
/** Whether database logging is enabled. */
|
||||||
@Env('DB_LOGGING_ENABLED')
|
@Env('DB_LOGGING_ENABLED')
|
||||||
readonly enabled: boolean = false;
|
enabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database logging level. Requires `DB_LOGGING_MAX_EXECUTION_TIME` to be higher than `0`.
|
* Database logging level. Requires `DB_LOGGING_MAX_EXECUTION_TIME` to be higher than `0`.
|
||||||
*/
|
*/
|
||||||
@Env('DB_LOGGING_OPTIONS')
|
@Env('DB_LOGGING_OPTIONS')
|
||||||
readonly options: 'query' | 'error' | 'schema' | 'warn' | 'info' | 'log' | 'all' = 'error';
|
options: 'query' | 'error' | 'schema' | 'warn' | 'info' | 'log' | 'all' = 'error';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only queries that exceed this time (ms) will be logged. Set `0` to disable.
|
* Only queries that exceed this time (ms) will be logged. Set `0` to disable.
|
||||||
*/
|
*/
|
||||||
@Env('DB_LOGGING_MAX_EXECUTION_TIME')
|
@Env('DB_LOGGING_MAX_EXECUTION_TIME')
|
||||||
readonly maxQueryExecutionTime: number = 0;
|
maxQueryExecutionTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
|
@ -26,97 +26,97 @@ class PostgresSSLConfig {
|
||||||
* If `DB_POSTGRESDB_SSL_CA`, `DB_POSTGRESDB_SSL_CERT`, or `DB_POSTGRESDB_SSL_KEY` are defined, `DB_POSTGRESDB_SSL_ENABLED` defaults to `true`.
|
* If `DB_POSTGRESDB_SSL_CA`, `DB_POSTGRESDB_SSL_CERT`, or `DB_POSTGRESDB_SSL_KEY` are defined, `DB_POSTGRESDB_SSL_ENABLED` defaults to `true`.
|
||||||
*/
|
*/
|
||||||
@Env('DB_POSTGRESDB_SSL_ENABLED')
|
@Env('DB_POSTGRESDB_SSL_ENABLED')
|
||||||
readonly enabled: boolean = false;
|
enabled = false;
|
||||||
|
|
||||||
/** SSL certificate authority */
|
/** SSL certificate authority */
|
||||||
@Env('DB_POSTGRESDB_SSL_CA')
|
@Env('DB_POSTGRESDB_SSL_CA')
|
||||||
readonly ca: string = '';
|
ca = '';
|
||||||
|
|
||||||
/** SSL certificate */
|
/** SSL certificate */
|
||||||
@Env('DB_POSTGRESDB_SSL_CERT')
|
@Env('DB_POSTGRESDB_SSL_CERT')
|
||||||
readonly cert: string = '';
|
cert = '';
|
||||||
|
|
||||||
/** SSL key */
|
/** SSL key */
|
||||||
@Env('DB_POSTGRESDB_SSL_KEY')
|
@Env('DB_POSTGRESDB_SSL_KEY')
|
||||||
readonly key: string = '';
|
key = '';
|
||||||
|
|
||||||
/** If unauthorized SSL connections should be rejected */
|
/** If unauthorized SSL connections should be rejected */
|
||||||
@Env('DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED')
|
@Env('DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED')
|
||||||
readonly rejectUnauthorized: boolean = true;
|
rejectUnauthorized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class PostgresConfig {
|
class PostgresConfig {
|
||||||
/** Postgres database name */
|
/** Postgres database name */
|
||||||
@Env('DB_POSTGRESDB_DATABASE')
|
@Env('DB_POSTGRESDB_DATABASE')
|
||||||
database: string = 'n8n';
|
database = 'n8n';
|
||||||
|
|
||||||
/** Postgres database host */
|
/** Postgres database host */
|
||||||
@Env('DB_POSTGRESDB_HOST')
|
@Env('DB_POSTGRESDB_HOST')
|
||||||
readonly host: string = 'localhost';
|
host = 'localhost';
|
||||||
|
|
||||||
/** Postgres database password */
|
/** Postgres database password */
|
||||||
@Env('DB_POSTGRESDB_PASSWORD')
|
@Env('DB_POSTGRESDB_PASSWORD')
|
||||||
readonly password: string = '';
|
password = '';
|
||||||
|
|
||||||
/** Postgres database port */
|
/** Postgres database port */
|
||||||
@Env('DB_POSTGRESDB_PORT')
|
@Env('DB_POSTGRESDB_PORT')
|
||||||
readonly port: number = 5432;
|
port: number = 5432;
|
||||||
|
|
||||||
/** Postgres database user */
|
/** Postgres database user */
|
||||||
@Env('DB_POSTGRESDB_USER')
|
@Env('DB_POSTGRESDB_USER')
|
||||||
readonly user: string = 'postgres';
|
user = 'postgres';
|
||||||
|
|
||||||
/** Postgres database schema */
|
/** Postgres database schema */
|
||||||
@Env('DB_POSTGRESDB_SCHEMA')
|
@Env('DB_POSTGRESDB_SCHEMA')
|
||||||
readonly schema: string = 'public';
|
schema = 'public';
|
||||||
|
|
||||||
/** Postgres database pool size */
|
/** Postgres database pool size */
|
||||||
@Env('DB_POSTGRESDB_POOL_SIZE')
|
@Env('DB_POSTGRESDB_POOL_SIZE')
|
||||||
readonly poolSize = 2;
|
poolSize = 2;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly ssl: PostgresSSLConfig;
|
ssl: PostgresSSLConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class MysqlConfig {
|
class MysqlConfig {
|
||||||
/** @deprecated MySQL database name */
|
/** @deprecated MySQL database name */
|
||||||
@Env('DB_MYSQLDB_DATABASE')
|
@Env('DB_MYSQLDB_DATABASE')
|
||||||
database: string = 'n8n';
|
database = 'n8n';
|
||||||
|
|
||||||
/** MySQL database host */
|
/** MySQL database host */
|
||||||
@Env('DB_MYSQLDB_HOST')
|
@Env('DB_MYSQLDB_HOST')
|
||||||
readonly host: string = 'localhost';
|
host = 'localhost';
|
||||||
|
|
||||||
/** MySQL database password */
|
/** MySQL database password */
|
||||||
@Env('DB_MYSQLDB_PASSWORD')
|
@Env('DB_MYSQLDB_PASSWORD')
|
||||||
readonly password: string = '';
|
password = '';
|
||||||
|
|
||||||
/** MySQL database port */
|
/** MySQL database port */
|
||||||
@Env('DB_MYSQLDB_PORT')
|
@Env('DB_MYSQLDB_PORT')
|
||||||
readonly port: number = 3306;
|
port: number = 3306;
|
||||||
|
|
||||||
/** MySQL database user */
|
/** MySQL database user */
|
||||||
@Env('DB_MYSQLDB_USER')
|
@Env('DB_MYSQLDB_USER')
|
||||||
readonly user: string = 'root';
|
user = 'root';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class SqliteConfig {
|
class SqliteConfig {
|
||||||
/** SQLite database file name */
|
/** SQLite database file name */
|
||||||
@Env('DB_SQLITE_DATABASE')
|
@Env('DB_SQLITE_DATABASE')
|
||||||
readonly database: string = 'database.sqlite';
|
database = 'database.sqlite';
|
||||||
|
|
||||||
/** SQLite database pool size. Set to `0` to disable pooling. */
|
/** SQLite database pool size. Set to `0` to disable pooling. */
|
||||||
@Env('DB_SQLITE_POOL_SIZE')
|
@Env('DB_SQLITE_POOL_SIZE')
|
||||||
readonly poolSize: number = 0;
|
poolSize: number = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable SQLite WAL mode.
|
* Enable SQLite WAL mode.
|
||||||
*/
|
*/
|
||||||
@Env('DB_SQLITE_ENABLE_WAL')
|
@Env('DB_SQLITE_ENABLE_WAL')
|
||||||
readonly enableWAL: boolean = this.poolSize > 1;
|
enableWAL = this.poolSize > 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run `VACUUM` on startup to rebuild the database, reducing file size and optimizing indexes.
|
* Run `VACUUM` on startup to rebuild the database, reducing file size and optimizing indexes.
|
||||||
|
@ -124,7 +124,7 @@ class SqliteConfig {
|
||||||
* @warning Long-running blocking operation that will increase startup time.
|
* @warning Long-running blocking operation that will increase startup time.
|
||||||
*/
|
*/
|
||||||
@Env('DB_SQLITE_VACUUM_ON_STARTUP')
|
@Env('DB_SQLITE_VACUUM_ON_STARTUP')
|
||||||
readonly executeVacuumOnStartup: boolean = false;
|
executeVacuumOnStartup = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
|
@ -135,17 +135,17 @@ export class DatabaseConfig {
|
||||||
|
|
||||||
/** Prefix for table names */
|
/** Prefix for table names */
|
||||||
@Env('DB_TABLE_PREFIX')
|
@Env('DB_TABLE_PREFIX')
|
||||||
readonly tablePrefix: string = '';
|
tablePrefix = '';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly logging: LoggingConfig;
|
logging: LoggingConfig;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly postgresdb: PostgresConfig;
|
postgresdb: PostgresConfig;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly mysqldb: MysqlConfig;
|
mysqldb: MysqlConfig;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly sqlite: SqliteConfig;
|
sqlite: SqliteConfig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,75 +4,75 @@ import { Config, Env, Nested } from '../decorators';
|
||||||
export class SmtpAuth {
|
export class SmtpAuth {
|
||||||
/** SMTP login username */
|
/** SMTP login username */
|
||||||
@Env('N8N_SMTP_USER')
|
@Env('N8N_SMTP_USER')
|
||||||
readonly user: string = '';
|
user = '';
|
||||||
|
|
||||||
/** SMTP login password */
|
/** SMTP login password */
|
||||||
@Env('N8N_SMTP_PASS')
|
@Env('N8N_SMTP_PASS')
|
||||||
readonly pass: string = '';
|
pass = '';
|
||||||
|
|
||||||
/** SMTP OAuth Service Client */
|
/** SMTP OAuth Service Client */
|
||||||
@Env('N8N_SMTP_OAUTH_SERVICE_CLIENT')
|
@Env('N8N_SMTP_OAUTH_SERVICE_CLIENT')
|
||||||
readonly serviceClient: string = '';
|
serviceClient = '';
|
||||||
|
|
||||||
/** SMTP OAuth Private Key */
|
/** SMTP OAuth Private Key */
|
||||||
@Env('N8N_SMTP_OAUTH_PRIVATE_KEY')
|
@Env('N8N_SMTP_OAUTH_PRIVATE_KEY')
|
||||||
readonly privateKey: string = '';
|
privateKey = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class SmtpConfig {
|
export class SmtpConfig {
|
||||||
/** SMTP server host */
|
/** SMTP server host */
|
||||||
@Env('N8N_SMTP_HOST')
|
@Env('N8N_SMTP_HOST')
|
||||||
readonly host: string = '';
|
host = '';
|
||||||
|
|
||||||
/** SMTP server port */
|
/** SMTP server port */
|
||||||
@Env('N8N_SMTP_PORT')
|
@Env('N8N_SMTP_PORT')
|
||||||
readonly port: number = 465;
|
port: number = 465;
|
||||||
|
|
||||||
/** Whether to use SSL for SMTP */
|
/** Whether to use SSL for SMTP */
|
||||||
@Env('N8N_SMTP_SSL')
|
@Env('N8N_SMTP_SSL')
|
||||||
readonly secure: boolean = true;
|
secure: boolean = true;
|
||||||
|
|
||||||
/** Whether to use STARTTLS for SMTP when SSL is disabled */
|
/** Whether to use STARTTLS for SMTP when SSL is disabled */
|
||||||
@Env('N8N_SMTP_STARTTLS')
|
@Env('N8N_SMTP_STARTTLS')
|
||||||
readonly startTLS: boolean = true;
|
startTLS: boolean = true;
|
||||||
|
|
||||||
/** How to display sender name */
|
/** How to display sender name */
|
||||||
@Env('N8N_SMTP_SENDER')
|
@Env('N8N_SMTP_SENDER')
|
||||||
readonly sender: string = '';
|
sender = '';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly auth: SmtpAuth;
|
auth: SmtpAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class TemplateConfig {
|
export class TemplateConfig {
|
||||||
/** Overrides default HTML template for inviting new people (use full path) */
|
/** Overrides default HTML template for inviting new people (use full path) */
|
||||||
@Env('N8N_UM_EMAIL_TEMPLATES_INVITE')
|
@Env('N8N_UM_EMAIL_TEMPLATES_INVITE')
|
||||||
readonly invite: string = '';
|
invite = '';
|
||||||
|
|
||||||
/** Overrides default HTML template for resetting password (use full path) */
|
/** Overrides default HTML template for resetting password (use full path) */
|
||||||
@Env('N8N_UM_EMAIL_TEMPLATES_PWRESET')
|
@Env('N8N_UM_EMAIL_TEMPLATES_PWRESET')
|
||||||
readonly passwordReset: string = '';
|
passwordReset = '';
|
||||||
|
|
||||||
/** Overrides default HTML template for notifying that a workflow was shared (use full path) */
|
/** Overrides default HTML template for notifying that a workflow was shared (use full path) */
|
||||||
@Env('N8N_UM_EMAIL_TEMPLATES_WORKFLOW_SHARED')
|
@Env('N8N_UM_EMAIL_TEMPLATES_WORKFLOW_SHARED')
|
||||||
readonly workflowShared: string = '';
|
workflowShared = '';
|
||||||
|
|
||||||
/** Overrides default HTML template for notifying that credentials were shared (use full path) */
|
/** Overrides default HTML template for notifying that credentials were shared (use full path) */
|
||||||
@Env('N8N_UM_EMAIL_TEMPLATES_CREDENTIALS_SHARED')
|
@Env('N8N_UM_EMAIL_TEMPLATES_CREDENTIALS_SHARED')
|
||||||
readonly credentialsShared: string = '';
|
credentialsShared = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class EmailConfig {
|
export class EmailConfig {
|
||||||
/** How to send emails */
|
/** How to send emails */
|
||||||
@Env('N8N_EMAIL_MODE')
|
@Env('N8N_EMAIL_MODE')
|
||||||
readonly mode: '' | 'smtp' = 'smtp';
|
mode: '' | 'smtp' = 'smtp';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly smtp: SmtpConfig;
|
smtp: SmtpConfig;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly template: TemplateConfig;
|
template: TemplateConfig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,99 +4,99 @@ import { Config, Env, Nested } from '../decorators';
|
||||||
class PrometheusMetricsConfig {
|
class PrometheusMetricsConfig {
|
||||||
/** Whether to enable the `/metrics` endpoint to expose Prometheus metrics. */
|
/** Whether to enable the `/metrics` endpoint to expose Prometheus metrics. */
|
||||||
@Env('N8N_METRICS')
|
@Env('N8N_METRICS')
|
||||||
readonly enable: boolean = false;
|
enable = false;
|
||||||
|
|
||||||
/** Prefix for Prometheus metric names. */
|
/** Prefix for Prometheus metric names. */
|
||||||
@Env('N8N_METRICS_PREFIX')
|
@Env('N8N_METRICS_PREFIX')
|
||||||
readonly prefix: string = 'n8n_';
|
prefix = 'n8n_';
|
||||||
|
|
||||||
/** Whether to expose system and Node.js metrics. See: https://www.npmjs.com/package/prom-client */
|
/** Whether to expose system and Node.js metrics. See: https://www.npmjs.com/package/prom-client */
|
||||||
@Env('N8N_METRICS_INCLUDE_DEFAULT_METRICS')
|
@Env('N8N_METRICS_INCLUDE_DEFAULT_METRICS')
|
||||||
readonly includeDefaultMetrics = true;
|
includeDefaultMetrics = true;
|
||||||
|
|
||||||
/** Whether to include a label for workflow ID on workflow metrics. */
|
/** Whether to include a label for workflow ID on workflow metrics. */
|
||||||
@Env('N8N_METRICS_INCLUDE_WORKFLOW_ID_LABEL')
|
@Env('N8N_METRICS_INCLUDE_WORKFLOW_ID_LABEL')
|
||||||
readonly includeWorkflowIdLabel: boolean = false;
|
includeWorkflowIdLabel = false;
|
||||||
|
|
||||||
/** Whether to include a label for node type on node metrics. */
|
/** Whether to include a label for node type on node metrics. */
|
||||||
@Env('N8N_METRICS_INCLUDE_NODE_TYPE_LABEL')
|
@Env('N8N_METRICS_INCLUDE_NODE_TYPE_LABEL')
|
||||||
readonly includeNodeTypeLabel: boolean = false;
|
includeNodeTypeLabel = false;
|
||||||
|
|
||||||
/** Whether to include a label for credential type on credential metrics. */
|
/** Whether to include a label for credential type on credential metrics. */
|
||||||
@Env('N8N_METRICS_INCLUDE_CREDENTIAL_TYPE_LABEL')
|
@Env('N8N_METRICS_INCLUDE_CREDENTIAL_TYPE_LABEL')
|
||||||
readonly includeCredentialTypeLabel: boolean = false;
|
includeCredentialTypeLabel = false;
|
||||||
|
|
||||||
/** Whether to expose metrics for API endpoints. See: https://www.npmjs.com/package/express-prom-bundle */
|
/** Whether to expose metrics for API endpoints. See: https://www.npmjs.com/package/express-prom-bundle */
|
||||||
@Env('N8N_METRICS_INCLUDE_API_ENDPOINTS')
|
@Env('N8N_METRICS_INCLUDE_API_ENDPOINTS')
|
||||||
readonly includeApiEndpoints: boolean = false;
|
includeApiEndpoints = false;
|
||||||
|
|
||||||
/** Whether to include a label for the path of API endpoint calls. */
|
/** Whether to include a label for the path of API endpoint calls. */
|
||||||
@Env('N8N_METRICS_INCLUDE_API_PATH_LABEL')
|
@Env('N8N_METRICS_INCLUDE_API_PATH_LABEL')
|
||||||
readonly includeApiPathLabel: boolean = false;
|
includeApiPathLabel = false;
|
||||||
|
|
||||||
/** Whether to include a label for the HTTP method of API endpoint calls. */
|
/** Whether to include a label for the HTTP method of API endpoint calls. */
|
||||||
@Env('N8N_METRICS_INCLUDE_API_METHOD_LABEL')
|
@Env('N8N_METRICS_INCLUDE_API_METHOD_LABEL')
|
||||||
readonly includeApiMethodLabel: boolean = false;
|
includeApiMethodLabel = false;
|
||||||
|
|
||||||
/** Whether to include a label for the status code of API endpoint calls. */
|
/** Whether to include a label for the status code of API endpoint calls. */
|
||||||
@Env('N8N_METRICS_INCLUDE_API_STATUS_CODE_LABEL')
|
@Env('N8N_METRICS_INCLUDE_API_STATUS_CODE_LABEL')
|
||||||
readonly includeApiStatusCodeLabel: boolean = false;
|
includeApiStatusCodeLabel = false;
|
||||||
|
|
||||||
/** Whether to include metrics for cache hits and misses. */
|
/** Whether to include metrics for cache hits and misses. */
|
||||||
@Env('N8N_METRICS_INCLUDE_CACHE_METRICS')
|
@Env('N8N_METRICS_INCLUDE_CACHE_METRICS')
|
||||||
readonly includeCacheMetrics: boolean = false;
|
includeCacheMetrics = false;
|
||||||
|
|
||||||
/** Whether to include metrics derived from n8n's internal events */
|
/** Whether to include metrics derived from n8n's internal events */
|
||||||
@Env('N8N_METRICS_INCLUDE_MESSAGE_EVENT_BUS_METRICS')
|
@Env('N8N_METRICS_INCLUDE_MESSAGE_EVENT_BUS_METRICS')
|
||||||
readonly includeMessageEventBusMetrics: boolean = false;
|
includeMessageEventBusMetrics = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class EndpointsConfig {
|
export class EndpointsConfig {
|
||||||
/** Max payload size in MiB */
|
/** Max payload size in MiB */
|
||||||
@Env('N8N_PAYLOAD_SIZE_MAX')
|
@Env('N8N_PAYLOAD_SIZE_MAX')
|
||||||
readonly payloadSizeMax: number = 16;
|
payloadSizeMax: number = 16;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly metrics: PrometheusMetricsConfig;
|
metrics: PrometheusMetricsConfig;
|
||||||
|
|
||||||
/** Path segment for REST API endpoints. */
|
/** Path segment for REST API endpoints. */
|
||||||
@Env('N8N_ENDPOINT_REST')
|
@Env('N8N_ENDPOINT_REST')
|
||||||
readonly rest: string = 'rest';
|
rest = 'rest';
|
||||||
|
|
||||||
/** Path segment for form endpoints. */
|
/** Path segment for form endpoints. */
|
||||||
@Env('N8N_ENDPOINT_FORM')
|
@Env('N8N_ENDPOINT_FORM')
|
||||||
readonly form: string = 'form';
|
form = 'form';
|
||||||
|
|
||||||
/** Path segment for test form endpoints. */
|
/** Path segment for test form endpoints. */
|
||||||
@Env('N8N_ENDPOINT_FORM_TEST')
|
@Env('N8N_ENDPOINT_FORM_TEST')
|
||||||
readonly formTest: string = 'form-test';
|
formTest = 'form-test';
|
||||||
|
|
||||||
/** Path segment for waiting form endpoints. */
|
/** Path segment for waiting form endpoints. */
|
||||||
@Env('N8N_ENDPOINT_FORM_WAIT')
|
@Env('N8N_ENDPOINT_FORM_WAIT')
|
||||||
readonly formWaiting: string = 'form-waiting';
|
formWaiting = 'form-waiting';
|
||||||
|
|
||||||
/** Path segment for webhook endpoints. */
|
/** Path segment for webhook endpoints. */
|
||||||
@Env('N8N_ENDPOINT_WEBHOOK')
|
@Env('N8N_ENDPOINT_WEBHOOK')
|
||||||
readonly webhook: string = 'webhook';
|
webhook = 'webhook';
|
||||||
|
|
||||||
/** Path segment for test webhook endpoints. */
|
/** Path segment for test webhook endpoints. */
|
||||||
@Env('N8N_ENDPOINT_WEBHOOK_TEST')
|
@Env('N8N_ENDPOINT_WEBHOOK_TEST')
|
||||||
readonly webhookTest: string = 'webhook-test';
|
webhookTest = 'webhook-test';
|
||||||
|
|
||||||
/** Path segment for waiting webhook endpoints. */
|
/** Path segment for waiting webhook endpoints. */
|
||||||
@Env('N8N_ENDPOINT_WEBHOOK_WAIT')
|
@Env('N8N_ENDPOINT_WEBHOOK_WAIT')
|
||||||
readonly webhookWaiting: string = 'webhook-waiting';
|
webhookWaiting = 'webhook-waiting';
|
||||||
|
|
||||||
/** Whether to disable n8n's UI (frontend). */
|
/** Whether to disable n8n's UI (frontend). */
|
||||||
@Env('N8N_DISABLE_UI')
|
@Env('N8N_DISABLE_UI')
|
||||||
readonly disableUi: boolean = false;
|
disableUi = false;
|
||||||
|
|
||||||
/** Whether to disable production webhooks on the main process, when using webhook-specific processes. */
|
/** Whether to disable production webhooks on the main process, when using webhook-specific processes. */
|
||||||
@Env('N8N_DISABLE_PRODUCTION_MAIN_PROCESS')
|
@Env('N8N_DISABLE_PRODUCTION_MAIN_PROCESS')
|
||||||
readonly disableProductionWebhooksOnMainProcess: boolean = false;
|
disableProductionWebhooksOnMainProcess = false;
|
||||||
|
|
||||||
/** Colon-delimited list of additional endpoints to not open the UI on. */
|
/** Colon-delimited list of additional endpoints to not open the UI on. */
|
||||||
@Env('N8N_ADDITIONAL_NON_UI_ROUTES')
|
@Env('N8N_ADDITIONAL_NON_UI_ROUTES')
|
||||||
readonly additionalNonUIRoutes: string = '';
|
additionalNonUIRoutes = '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,30 +2,30 @@ import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class LogWriterConfig {
|
class LogWriterConfig {
|
||||||
/** Number of event log files to keep */
|
/* of event log files to keep */
|
||||||
@Env('N8N_EVENTBUS_LOGWRITER_KEEPLOGCOUNT')
|
@Env('N8N_EVENTBUS_LOGWRITER_KEEPLOGCOUNT')
|
||||||
readonly keepLogCount: number = 3;
|
keepLogCount = 3;
|
||||||
|
|
||||||
/** Max size (in KB) of an event log file before a new one is started */
|
/** Max size (in KB) of an event log file before a new one is started */
|
||||||
@Env('N8N_EVENTBUS_LOGWRITER_MAXFILESIZEINKB')
|
@Env('N8N_EVENTBUS_LOGWRITER_MAXFILESIZEINKB')
|
||||||
readonly maxFileSizeInKB: number = 10240; // 10 MB
|
maxFileSizeInKB = 10240; // 10 MB
|
||||||
|
|
||||||
/** Basename of event log file */
|
/** Basename of event log file */
|
||||||
@Env('N8N_EVENTBUS_LOGWRITER_LOGBASENAME')
|
@Env('N8N_EVENTBUS_LOGWRITER_LOGBASENAME')
|
||||||
readonly logBaseName: string = 'n8nEventLog';
|
logBaseName = 'n8nEventLog';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class EventBusConfig {
|
export class EventBusConfig {
|
||||||
/** How often (in ms) to check for unsent event messages. Can in rare cases cause a message to be sent twice. `0` to disable */
|
/** How often (in ms) to check for unsent event messages. Can in rare cases cause a message to be sent twice. `0` to disable */
|
||||||
@Env('N8N_EVENTBUS_CHECKUNSENTINTERVAL')
|
@Env('N8N_EVENTBUS_CHECKUNSENTINTERVAL')
|
||||||
readonly checkUnsentInterval: number = 0;
|
checkUnsentInterval = 0;
|
||||||
|
|
||||||
/** Endpoint to retrieve n8n version information from */
|
/** Endpoint to retrieve n8n version information from */
|
||||||
@Nested
|
@Nested
|
||||||
readonly logWriter: LogWriterConfig;
|
logWriter: LogWriterConfig;
|
||||||
|
|
||||||
/** Whether to recover execution details after a crash or only mark status executions as crashed. */
|
/** Whether to recover execution details after a crash or only mark status executions as crashed. */
|
||||||
@Env('N8N_EVENTBUS_RECOVERY_MODE')
|
@Env('N8N_EVENTBUS_RECOVERY_MODE')
|
||||||
readonly crashRecoveryMode: 'simple' | 'extensive' = 'extensive';
|
crashRecoveryMode: 'simple' | 'extensive' = 'extensive';
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { Config, Env } from '../decorators';
|
||||||
export class ExternalSecretsConfig {
|
export class ExternalSecretsConfig {
|
||||||
/** How often (in seconds) to check for secret updates */
|
/** How often (in seconds) to check for secret updates */
|
||||||
@Env('N8N_EXTERNAL_SECRETS_UPDATE_INTERVAL')
|
@Env('N8N_EXTERNAL_SECRETS_UPDATE_INTERVAL')
|
||||||
readonly updateInterval: number = 300;
|
updateInterval = 300;
|
||||||
|
|
||||||
/** Whether to prefer GET over LIST when fetching secrets from Hashicorp Vault */
|
/** Whether to prefer GET over LIST when fetching secrets from Hashicorp Vault */
|
||||||
@Env('N8N_EXTERNAL_SECRETS_PREFER_GET')
|
@Env('N8N_EXTERNAL_SECRETS_PREFER_GET')
|
||||||
readonly preferGet: boolean = false;
|
preferGet = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,39 +4,39 @@ import { Config, Env, Nested } from '../decorators';
|
||||||
class S3BucketConfig {
|
class S3BucketConfig {
|
||||||
/** Name of the n8n bucket in S3-compatible external storage */
|
/** Name of the n8n bucket in S3-compatible external storage */
|
||||||
@Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME')
|
@Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME')
|
||||||
readonly name: string = '';
|
name = '';
|
||||||
|
|
||||||
/** Region of the n8n bucket in S3-compatible external storage @example "us-east-1" */
|
/** Region of the n8n bucket in S3-compatible external storage @example "us-east-1" */
|
||||||
@Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION')
|
@Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION')
|
||||||
readonly region: string = '';
|
region = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class S3CredentialsConfig {
|
class S3CredentialsConfig {
|
||||||
/** Access key in S3-compatible external storage */
|
/** Access key in S3-compatible external storage */
|
||||||
@Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY')
|
@Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY')
|
||||||
readonly accessKey: string = '';
|
accessKey = '';
|
||||||
|
|
||||||
/** Access secret in S3-compatible external storage */
|
/** Access secret in S3-compatible external storage */
|
||||||
@Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET')
|
@Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET')
|
||||||
readonly accessSecret: string = '';
|
accessSecret = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class S3Config {
|
class S3Config {
|
||||||
/** Host of the n8n bucket in S3-compatible external storage @example "s3.us-east-1.amazonaws.com" */
|
/** Host of the n8n bucket in S3-compatible external storage @example "s3.us-east-1.amazonaws.com" */
|
||||||
@Env('N8N_EXTERNAL_STORAGE_S3_HOST')
|
@Env('N8N_EXTERNAL_STORAGE_S3_HOST')
|
||||||
readonly host: string = '';
|
host = '';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly bucket: S3BucketConfig;
|
bucket: S3BucketConfig;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly credentials: S3CredentialsConfig;
|
credentials: S3CredentialsConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class ExternalStorageConfig {
|
export class ExternalStorageConfig {
|
||||||
@Nested
|
@Nested
|
||||||
readonly s3: S3Config;
|
s3: S3Config;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,16 +31,16 @@ class CommunityPackagesConfig {
|
||||||
export class NodesConfig {
|
export class NodesConfig {
|
||||||
/** Node types to load. Includes all if unspecified. @example '["n8n-nodes-base.hackerNews"]' */
|
/** Node types to load. Includes all if unspecified. @example '["n8n-nodes-base.hackerNews"]' */
|
||||||
@Env('NODES_INCLUDE')
|
@Env('NODES_INCLUDE')
|
||||||
readonly include: JsonStringArray = [];
|
include: JsonStringArray = [];
|
||||||
|
|
||||||
/** Node types not to load. Excludes none if unspecified. @example '["n8n-nodes-base.hackerNews"]' */
|
/** Node types not to load. Excludes none if unspecified. @example '["n8n-nodes-base.hackerNews"]' */
|
||||||
@Env('NODES_EXCLUDE')
|
@Env('NODES_EXCLUDE')
|
||||||
readonly exclude: JsonStringArray = [];
|
exclude: JsonStringArray = [];
|
||||||
|
|
||||||
/** Node type to use as error trigger */
|
/** Node type to use as error trigger */
|
||||||
@Env('NODES_ERROR_TRIGGER_TYPE')
|
@Env('NODES_ERROR_TRIGGER_TYPE')
|
||||||
readonly errorTriggerType: string = 'n8n-nodes-base.errorTrigger';
|
errorTriggerType = 'n8n-nodes-base.errorTrigger';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly communityPackages: CommunityPackagesConfig;
|
communityPackages: CommunityPackagesConfig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,13 @@ import { Config, Env } from '../decorators';
|
||||||
export class PublicApiConfig {
|
export class PublicApiConfig {
|
||||||
/** Whether to disable the Public API */
|
/** Whether to disable the Public API */
|
||||||
@Env('N8N_PUBLIC_API_DISABLED')
|
@Env('N8N_PUBLIC_API_DISABLED')
|
||||||
readonly disabled: boolean = false;
|
disabled = false;
|
||||||
|
|
||||||
/** Path segment for the Public API */
|
/** Path segment for the Public API */
|
||||||
@Env('N8N_PUBLIC_API_ENDPOINT')
|
@Env('N8N_PUBLIC_API_ENDPOINT')
|
||||||
readonly path: string = 'api';
|
path = 'api';
|
||||||
|
|
||||||
/** Whether to disable the Swagger UI for the Public API */
|
/** Whether to disable the Swagger UI for the Public API */
|
||||||
@Env('N8N_PUBLIC_API_SWAGGERUI_DISABLED')
|
@Env('N8N_PUBLIC_API_SWAGGERUI_DISABLED')
|
||||||
readonly swaggerUiDisabled: boolean = false;
|
swaggerUiDisabled = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { Config, Env } from '../decorators';
|
||||||
export class TemplatesConfig {
|
export class TemplatesConfig {
|
||||||
/** Whether to load workflow templates. */
|
/** Whether to load workflow templates. */
|
||||||
@Env('N8N_TEMPLATES_ENABLED')
|
@Env('N8N_TEMPLATES_ENABLED')
|
||||||
readonly enabled: boolean = true;
|
enabled = true;
|
||||||
|
|
||||||
/** Host to retrieve workflow templates from endpoints. */
|
/** Host to retrieve workflow templates from endpoints. */
|
||||||
@Env('N8N_TEMPLATES_HOST')
|
@Env('N8N_TEMPLATES_HOST')
|
||||||
readonly host: string = 'https://api.n8n.io/api/';
|
host = 'https://api.n8n.io/api/';
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,13 @@ import { Config, Env } from '../decorators';
|
||||||
export class VersionNotificationsConfig {
|
export class VersionNotificationsConfig {
|
||||||
/** Whether to request notifications about new n8n versions */
|
/** Whether to request notifications about new n8n versions */
|
||||||
@Env('N8N_VERSION_NOTIFICATIONS_ENABLED')
|
@Env('N8N_VERSION_NOTIFICATIONS_ENABLED')
|
||||||
readonly enabled: boolean = true;
|
enabled = true;
|
||||||
|
|
||||||
/** Endpoint to retrieve n8n version information from */
|
/** Endpoint to retrieve n8n version information from */
|
||||||
@Env('N8N_VERSION_NOTIFICATIONS_ENDPOINT')
|
@Env('N8N_VERSION_NOTIFICATIONS_ENDPOINT')
|
||||||
readonly endpoint: string = 'https://api.n8n.io/api/versions/';
|
endpoint = 'https://api.n8n.io/api/versions/';
|
||||||
|
|
||||||
/** URL for versions panel to page instructing user on how to update n8n instance */
|
/** URL for versions panel to page instructing user on how to update n8n instance */
|
||||||
@Env('N8N_VERSION_NOTIFICATIONS_INFO_URL')
|
@Env('N8N_VERSION_NOTIFICATIONS_INFO_URL')
|
||||||
readonly infoUrl: string = 'https://docs.n8n.io/hosting/installation/updating/';
|
infoUrl = 'https://docs.n8n.io/hosting/installation/updating/';
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,14 @@ import { Config, Env } from '../decorators';
|
||||||
export class WorkflowsConfig {
|
export class WorkflowsConfig {
|
||||||
/** Default name for workflow */
|
/** Default name for workflow */
|
||||||
@Env('WORKFLOWS_DEFAULT_NAME')
|
@Env('WORKFLOWS_DEFAULT_NAME')
|
||||||
readonly defaultName: string = 'My workflow';
|
defaultName = 'My workflow';
|
||||||
|
|
||||||
/** Show onboarding flow in new workflow */
|
/** Show onboarding flow in new workflow */
|
||||||
@Env('N8N_ONBOARDING_FLOW_DISABLED')
|
@Env('N8N_ONBOARDING_FLOW_DISABLED')
|
||||||
readonly onboardingFlowDisabled: boolean = false;
|
onboardingFlowDisabled = false;
|
||||||
|
|
||||||
/** Default option for which workflows may call the current workflow */
|
/** Default option for which workflows may call the current workflow */
|
||||||
@Env('N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION')
|
@Env('N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION')
|
||||||
readonly callerPolicyDefaultOption:
|
callerPolicyDefaultOption: 'any' | 'none' | 'workflowsFromAList' | 'workflowsFromSameOwner' =
|
||||||
| 'any'
|
'workflowsFromSameOwner';
|
||||||
| 'none'
|
|
||||||
| 'workflowsFromAList'
|
|
||||||
| 'workflowsFromSameOwner' = 'workflowsFromSameOwner';
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { NodesConfig } from './configs/nodes';
|
||||||
import { ExternalStorageConfig } from './configs/external-storage';
|
import { ExternalStorageConfig } from './configs/external-storage';
|
||||||
import { WorkflowsConfig } from './configs/workflows';
|
import { WorkflowsConfig } from './configs/workflows';
|
||||||
import { EndpointsConfig } from './configs/endpoints';
|
import { EndpointsConfig } from './configs/endpoints';
|
||||||
|
import { CacheConfig } from './configs/cache';
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class UserManagementConfig {
|
class UserManagementConfig {
|
||||||
|
@ -75,4 +76,7 @@ export class GlobalConfig {
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
readonly endpoints: EndpointsConfig;
|
readonly endpoints: EndpointsConfig;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
readonly cache: CacheConfig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,17 @@ describe('GlobalConfig', () => {
|
||||||
webhookTest: 'webhook-test',
|
webhookTest: 'webhook-test',
|
||||||
webhookWaiting: 'webhook-waiting',
|
webhookWaiting: 'webhook-waiting',
|
||||||
},
|
},
|
||||||
|
cache: {
|
||||||
|
backend: 'auto',
|
||||||
|
memory: {
|
||||||
|
maxSize: 3145728,
|
||||||
|
ttl: 3600000,
|
||||||
|
},
|
||||||
|
redis: {
|
||||||
|
prefix: 'redis',
|
||||||
|
ttl: 3600000,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should use all default values when no env variables are defined', () => {
|
it('should use all default values when no env variables are defined', () => {
|
||||||
|
|
|
@ -660,43 +660,6 @@ export const schema = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
cache: {
|
|
||||||
backend: {
|
|
||||||
doc: 'Backend to use for caching',
|
|
||||||
format: ['memory', 'redis', 'auto'] as const,
|
|
||||||
default: 'auto',
|
|
||||||
env: 'N8N_CACHE_BACKEND',
|
|
||||||
},
|
|
||||||
memory: {
|
|
||||||
maxSize: {
|
|
||||||
doc: 'Maximum size of memory cache in bytes',
|
|
||||||
format: Number,
|
|
||||||
default: 3 * 1024 * 1024, // 3 MB
|
|
||||||
env: 'N8N_CACHE_MEMORY_MAX_SIZE',
|
|
||||||
},
|
|
||||||
ttl: {
|
|
||||||
doc: 'Time to live for cached items in memory (in ms)',
|
|
||||||
format: Number,
|
|
||||||
default: 3600 * 1000, // 1 hour
|
|
||||||
env: 'N8N_CACHE_MEMORY_TTL',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
redis: {
|
|
||||||
prefix: {
|
|
||||||
doc: 'Prefix for all cache keys',
|
|
||||||
format: String,
|
|
||||||
default: 'cache',
|
|
||||||
env: 'N8N_CACHE_REDIS_KEY_PREFIX',
|
|
||||||
},
|
|
||||||
ttl: {
|
|
||||||
doc: 'Time to live for cached items in redis (in ms), 0 for no TTL',
|
|
||||||
format: Number,
|
|
||||||
default: 3600 * 1000, // 1 hour
|
|
||||||
env: 'N8N_CACHE_REDIS_TTL',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @important Do not remove until after cloud hooks are updated to stop using convict config.
|
* @important Do not remove until after cloud hooks are updated to stop using convict config.
|
||||||
*/
|
*/
|
||||||
|
|
19
packages/cli/src/services/cache/cache.service.ts
vendored
19
packages/cli/src/services/cache/cache.service.ts
vendored
|
@ -13,6 +13,7 @@ import type {
|
||||||
} from '@/services/cache/cache.types';
|
} from '@/services/cache/cache.types';
|
||||||
import { TIME } from '@/constants';
|
import { TIME } from '@/constants';
|
||||||
import { TypedEmitter } from '@/TypedEmitter';
|
import { TypedEmitter } from '@/TypedEmitter';
|
||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
|
|
||||||
type CacheEvents = {
|
type CacheEvents = {
|
||||||
'metrics.cache.hit': never;
|
'metrics.cache.hit': never;
|
||||||
|
@ -22,12 +23,15 @@ type CacheEvents = {
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class CacheService extends TypedEmitter<CacheEvents> {
|
export class CacheService extends TypedEmitter<CacheEvents> {
|
||||||
|
constructor(private readonly globalConfig: GlobalConfig) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
private cache: TaggedRedisCache | TaggedMemoryCache;
|
private cache: TaggedRedisCache | TaggedMemoryCache;
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
const backend = config.getEnv('cache.backend');
|
const { backend } = this.globalConfig.cache;
|
||||||
const mode = config.getEnv('executions.mode');
|
const mode = config.getEnv('executions.mode');
|
||||||
const ttl = config.getEnv('cache.redis.ttl');
|
|
||||||
|
|
||||||
const useRedis = backend === 'redis' || (backend === 'auto' && mode === 'queue');
|
const useRedis = backend === 'redis' || (backend === 'auto' && mode === 'queue');
|
||||||
|
|
||||||
|
@ -36,8 +40,9 @@ export class CacheService extends TypedEmitter<CacheEvents> {
|
||||||
const redisClientService = Container.get(RedisClientService);
|
const redisClientService = Container.get(RedisClientService);
|
||||||
|
|
||||||
const prefixBase = config.getEnv('redis.prefix');
|
const prefixBase = config.getEnv('redis.prefix');
|
||||||
const cachePrefix = config.getEnv('cache.redis.prefix');
|
const prefix = redisClientService.toValidPrefix(
|
||||||
const prefix = redisClientService.toValidPrefix(`${prefixBase}:${cachePrefix}:`);
|
`${prefixBase}:${this.globalConfig.cache.redis.prefix}:`,
|
||||||
|
);
|
||||||
|
|
||||||
const redisClient = redisClientService.createClient({
|
const redisClient = redisClientService.createClient({
|
||||||
type: 'client(cache)',
|
type: 'client(cache)',
|
||||||
|
@ -45,7 +50,9 @@ export class CacheService extends TypedEmitter<CacheEvents> {
|
||||||
});
|
});
|
||||||
|
|
||||||
const { redisStoreUsingClient } = await import('@/services/cache/redis.cache-manager');
|
const { redisStoreUsingClient } = await import('@/services/cache/redis.cache-manager');
|
||||||
const redisStore = redisStoreUsingClient(redisClient, { ttl });
|
const redisStore = redisStoreUsingClient(redisClient, {
|
||||||
|
ttl: this.globalConfig.cache.redis.ttl,
|
||||||
|
});
|
||||||
|
|
||||||
const redisCache = await caching(redisStore);
|
const redisCache = await caching(redisStore);
|
||||||
|
|
||||||
|
@ -54,7 +61,7 @@ export class CacheService extends TypedEmitter<CacheEvents> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxSize = config.getEnv('cache.memory.maxSize');
|
const { maxSize, ttl } = this.globalConfig.cache.memory;
|
||||||
|
|
||||||
const sizeCalculation = (item: unknown) => {
|
const sizeCalculation = (item: unknown) => {
|
||||||
const str = jsonStringify(item, { replaceCircularRefs: true });
|
const str = jsonStringify(item, { replaceCircularRefs: true });
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import { ActivationErrorsService } from '@/ActivationErrors.service';
|
import { ActivationErrorsService } from '@/ActivationErrors.service';
|
||||||
import { CacheService } from '@/services/cache/cache.service';
|
import { CacheService } from '@/services/cache/cache.service';
|
||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
|
import { mockInstance } from '@test/mocking';
|
||||||
|
|
||||||
describe('ActivationErrorsService', () => {
|
describe('ActivationErrorsService', () => {
|
||||||
const cacheService = new CacheService();
|
const globalConfig = mockInstance(GlobalConfig, {
|
||||||
|
cache: { backend: 'memory', memory: { maxSize: 3 * 1024 * 1024, ttl: 3600 * 1000 } },
|
||||||
|
});
|
||||||
|
const cacheService = new CacheService(globalConfig);
|
||||||
const activationErrorsService = new ActivationErrorsService(cacheService);
|
const activationErrorsService = new ActivationErrorsService(cacheService);
|
||||||
|
|
||||||
const firstWorkflowId = 'GSG0etbfTA2CNPDX';
|
const firstWorkflowId = 'GSG0etbfTA2CNPDX';
|
||||||
|
|
|
@ -12,8 +12,8 @@ jest.unmock('@/eventbus/MessageEventBus/MessageEventBus');
|
||||||
const toLines = (response: Response) => response.text.trim().split('\n');
|
const toLines = (response: Response) => response.text.trim().split('\n');
|
||||||
|
|
||||||
const globalConfig = Container.get(GlobalConfig);
|
const globalConfig = Container.get(GlobalConfig);
|
||||||
// @ts-expect-error `metrics` is a readonly property
|
|
||||||
globalConfig.endpoints.metrics = {
|
globalConfig.endpoints.metrics = {
|
||||||
|
enable: true,
|
||||||
prefix: 'n8n_test_',
|
prefix: 'n8n_test_',
|
||||||
includeDefaultMetrics: true,
|
includeDefaultMetrics: true,
|
||||||
includeApiEndpoints: true,
|
includeApiEndpoints: true,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { CacheService } from '@/services/cache/cache.service';
|
import { CacheService } from '@/services/cache/cache.service';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { sleep } from 'n8n-workflow';
|
import { sleep } from 'n8n-workflow';
|
||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
jest.mock('ioredis', () => {
|
jest.mock('ioredis', () => {
|
||||||
const Redis = require('ioredis-mock');
|
const Redis = require('ioredis-mock');
|
||||||
|
@ -13,10 +15,12 @@ jest.mock('ioredis', () => {
|
||||||
for (const backend of ['memory', 'redis'] as const) {
|
for (const backend of ['memory', 'redis'] as const) {
|
||||||
describe(backend, () => {
|
describe(backend, () => {
|
||||||
let cacheService: CacheService;
|
let cacheService: CacheService;
|
||||||
|
let globalConfig: GlobalConfig;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
config.set('cache.backend', backend);
|
globalConfig = Container.get(GlobalConfig);
|
||||||
cacheService = new CacheService();
|
globalConfig.cache.backend = backend;
|
||||||
|
cacheService = new CacheService(globalConfig);
|
||||||
await cacheService.init();
|
await cacheService.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -43,7 +47,7 @@ for (const backend of ['memory', 'redis'] as const) {
|
||||||
|
|
||||||
if (backend === 'memory') {
|
if (backend === 'memory') {
|
||||||
test('should honor max size when enough', async () => {
|
test('should honor max size when enough', async () => {
|
||||||
config.set('cache.memory.maxSize', 16); // enough bytes for "withoutUnicode"
|
globalConfig.cache.memory.maxSize = 16; // enough bytes for "withoutUnicode"
|
||||||
|
|
||||||
await cacheService.init();
|
await cacheService.init();
|
||||||
await cacheService.set('key', 'withoutUnicode');
|
await cacheService.set('key', 'withoutUnicode');
|
||||||
|
@ -51,12 +55,12 @@ for (const backend of ['memory', 'redis'] as const) {
|
||||||
await expect(cacheService.get('key')).resolves.toBe('withoutUnicode');
|
await expect(cacheService.get('key')).resolves.toBe('withoutUnicode');
|
||||||
|
|
||||||
// restore
|
// restore
|
||||||
config.set('cache.memory.maxSize', 3 * 1024 * 1024);
|
globalConfig.cache.memory.maxSize = 3 * 1024 * 1024;
|
||||||
await cacheService.init();
|
await cacheService.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should honor max size when not enough', async () => {
|
test('should honor max size when not enough', async () => {
|
||||||
config.set('cache.memory.maxSize', 16); // not enough bytes for "withUnicodeԱԲԳ"
|
globalConfig.cache.memory.maxSize = 16; // not enough bytes for "withUnicodeԱԲԳ"
|
||||||
|
|
||||||
await cacheService.init();
|
await cacheService.init();
|
||||||
await cacheService.set('key', 'withUnicodeԱԲԳ');
|
await cacheService.set('key', 'withUnicodeԱԲԳ');
|
||||||
|
@ -64,7 +68,8 @@ for (const backend of ['memory', 'redis'] as const) {
|
||||||
await expect(cacheService.get('key')).resolves.toBeUndefined();
|
await expect(cacheService.get('key')).resolves.toBeUndefined();
|
||||||
|
|
||||||
// restore
|
// restore
|
||||||
config.set('cache.memory.maxSize', 3 * 1024 * 1024);
|
globalConfig.cache.memory.maxSize = 3 * 1024 * 1024;
|
||||||
|
// restore
|
||||||
await cacheService.init();
|
await cacheService.init();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue