mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2026-09-22 01:50:42 +02:00
* adds ExecutionEvents view modal to ExecutionList * fix time rendering and remove wf column * checks for unfinished executions and fails them * prevent re-setting stoppedAt for execution * some cleanup / manually create rundata after crash * quicksave * remove Threads lib, log worker rewrite * cleanup comment * fix sentry destination return value * test for tests... * run tests with single worker * fix tests * remove console log * add endpoint for execution data recovery * lint cleanup and some refactoring * fix accidental recursion * remove cyclic imports * add rundata recovery to Workflowrunner * remove comments * cleanup and refactor * adds a status field to executions * setExecutionStatus on queued worker * fix onWorkflowPostExecute * set waiting from worker * get crashed status into frontend * remove comment * merge fix * cleanup * catch empty rundata in recovery * refactor IExecutionsSummary and inject nodeExecution Errors * reduce default event log size to 10mb from 100mb * add per node execution status * lint fix * merge and lint fix * phrasing change * improve preview rendering and messaging * remove debug * Improve partial rundata recovery * fix labels * fix line through * send manual rundata to ui at crash * some type and msg push fixes * improve recovered item rendering in preview * update workflowStatistics on recover * merge fix * review fixes * merge fix * notify eventbus when ui is back up * add a small timeout to make sure the UI is back up * increase reconnect timeout to 30s * adjust recover timeout and ui connection lost msg * do not stop execution in editor after x reconnects * add executionRecovered push event * fix recovered connection not green * remove reconnect toast and merge existing rundata * merge editor and recovered data for own mode
127 lines
3.6 KiB
TypeScript
127 lines
3.6 KiB
TypeScript
import { v4 as uuid } from 'uuid';
|
|
import type { INodeCredentials, MessageEventBusDestinationOptions } from 'n8n-workflow';
|
|
import { LoggerProxy, MessageEventBusDestinationTypeNames } from 'n8n-workflow';
|
|
import * as Db from '@/Db';
|
|
import type { AbstractEventMessage } from '../EventMessageClasses/AbstractEventMessage';
|
|
import type { EventMessageTypes } from '../EventMessageClasses';
|
|
import type { DeleteResult, InsertResult } from 'typeorm';
|
|
import type { EventMessageConfirmSource } from '../EventMessageClasses/EventMessageConfirm';
|
|
import type { MessageEventBus, MessageWithCallback } from '../MessageEventBus/MessageEventBus';
|
|
|
|
export abstract class MessageEventBusDestination implements MessageEventBusDestinationOptions {
|
|
// Since you can't have static abstract functions - this just serves as a reminder that you need to implement these. Please.
|
|
// static abstract deserialize(): MessageEventBusDestination | null;
|
|
readonly id: string;
|
|
|
|
readonly eventBusInstance: MessageEventBus;
|
|
|
|
__type: MessageEventBusDestinationTypeNames;
|
|
|
|
label: string;
|
|
|
|
enabled: boolean;
|
|
|
|
subscribedEvents: string[];
|
|
|
|
credentials: INodeCredentials = {};
|
|
|
|
anonymizeAuditMessages: boolean;
|
|
|
|
constructor(eventBusInstance: MessageEventBus, options: MessageEventBusDestinationOptions) {
|
|
this.eventBusInstance = eventBusInstance;
|
|
this.id = !options.id || options.id.length !== 36 ? uuid() : options.id;
|
|
this.__type = options.__type ?? MessageEventBusDestinationTypeNames.abstract;
|
|
this.label = options.label ?? 'Log Destination';
|
|
this.enabled = options.enabled ?? false;
|
|
this.subscribedEvents = options.subscribedEvents ?? [];
|
|
this.anonymizeAuditMessages = options.anonymizeAuditMessages ?? false;
|
|
if (options.credentials) this.credentials = options.credentials;
|
|
LoggerProxy.debug(`${this.__type}(${this.id}) event destination constructed`);
|
|
}
|
|
|
|
startListening() {
|
|
if (this.enabled) {
|
|
this.eventBusInstance.on(
|
|
this.getId(),
|
|
async (
|
|
msg: EventMessageTypes,
|
|
confirmCallback: (message: EventMessageTypes, src: EventMessageConfirmSource) => void,
|
|
) => {
|
|
await this.receiveFromEventBus({ msg, confirmCallback });
|
|
},
|
|
);
|
|
LoggerProxy.debug(`${this.id} listener started`);
|
|
}
|
|
}
|
|
|
|
stopListening() {
|
|
this.eventBusInstance.removeAllListeners(this.getId());
|
|
}
|
|
|
|
enable() {
|
|
this.enabled = true;
|
|
this.startListening();
|
|
}
|
|
|
|
disable() {
|
|
this.enabled = false;
|
|
this.stopListening();
|
|
}
|
|
|
|
getId() {
|
|
return this.id;
|
|
}
|
|
|
|
hasSubscribedToEvent(msg: AbstractEventMessage) {
|
|
if (!this.enabled) return false;
|
|
for (const eventName of this.subscribedEvents) {
|
|
if (eventName === '*' || msg.eventName.startsWith(eventName)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async saveToDb() {
|
|
const data = {
|
|
id: this.getId(),
|
|
destination: this.serialize(),
|
|
};
|
|
const dbResult: InsertResult = await Db.collections.EventDestinations.upsert(data, {
|
|
skipUpdateIfNoValuesChanged: true,
|
|
conflictPaths: ['id'],
|
|
});
|
|
return dbResult;
|
|
}
|
|
|
|
async deleteFromDb() {
|
|
return MessageEventBusDestination.deleteFromDb(this.getId());
|
|
}
|
|
|
|
static async deleteFromDb(id: string): Promise<DeleteResult> {
|
|
const dbResult = await Db.collections.EventDestinations.delete({ id });
|
|
return dbResult;
|
|
}
|
|
|
|
serialize(): MessageEventBusDestinationOptions {
|
|
return {
|
|
__type: this.__type,
|
|
id: this.getId(),
|
|
label: this.label,
|
|
enabled: this.enabled,
|
|
subscribedEvents: this.subscribedEvents,
|
|
anonymizeAuditMessages: this.anonymizeAuditMessages,
|
|
};
|
|
}
|
|
|
|
abstract receiveFromEventBus(emitterPayload: MessageWithCallback): Promise<boolean>;
|
|
|
|
toString() {
|
|
return JSON.stringify(this.serialize());
|
|
}
|
|
|
|
close(): void | Promise<void> {
|
|
this.stopListening();
|
|
}
|
|
}
|