-
Notifications
You must be signed in to change notification settings - Fork 9.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(core): Move WorkflowHooks to core, improve type-safety, and add tests (no-changelog) #12364
base: master
Are you sure you want to change the base?
Conversation
da7898e
to
8018023
Compare
Codecov ReportAttention: Patch coverage is 📢 Thoughts on this report? Let us know! |
0ac5410
to
f3cbdaf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll come back later to finish reviewing and do some testing.
@@ -136,14 +142,12 @@ export class WorkflowRunner { | |||
try { | |||
await this.permissionChecker.check(workflowId, nodes); | |||
} catch (error) { | |||
const executionHooksFactory = Container.get(ExecutionHooksFactory); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we not injecting ExecutionHooksFactory
in the constructor? Same below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cyclic dependency. we needs a some serious rearchitecting/refactoring of this code to break that cycles.
this.activeExecutions.resolveResponsePromise(executionId, response); | ||
}, | ||
]; | ||
additionalData.hooks.addHook('sendResponse', async (response) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make addHook
accept sync and async functions? For less noise. Applies in a lot of other places as well.
additionalData.hooks.addHook('sendResponse', async (response) => { | |
additionalData.hooks.addHook('sendResponse', (response) => { |
// TODO: For realtime jobs should probably also not do retry or not retry if they are older than x seconds. | ||
// Check if they get retried by default and how often. | ||
let job: Job; | ||
let hooks: WorkflowHooks; | ||
let lifecycleHooks: ExecutionHooks; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See note on naming at execution-hooks.ts
declare module 'n8n-workflow' { | ||
interface IWorkflowExecuteAdditionalData { | ||
hooks?: ExecutionHooks; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Come back later to check if this is needed.
@@ -46,26 +46,20 @@ export class TriggersAndPollers { | |||
|
|||
// Add the manual trigger response which resolves when the first time data got emitted | |||
triggerResponse!.manualTriggerResponse = new Promise((resolve, reject) => { | |||
const hooks = additionalData.hooks!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we assert()
instead of !
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can. but I actually prefer to fix the typing, since these should always be available. The issue is that we've always hacked execution engine to do credential testing, and to keep the that legacy credential testing mechanism, we need to keep this optional.
Maybe we should redo credential testing first? 🤔
return hooks; | ||
} | ||
|
||
private addPreExecuteHooks(hooks: ExecutionHooks) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's called PreExecute
but adds a nodeExecuteAfter
callback? Can we find a better name for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried, but the only solution I came up was to break this up method into separate methods, and name those appropriately. I'd prefer to do that in another PR.
}); | ||
} | ||
|
||
private addEventHooks(hooks: ExecutionHooks) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Named like this I'd expect to see all events (i.e. points in execution lifecycle) but the important one workflowExecuteAfter
is missing here.
}); | ||
} | ||
|
||
/** Returns hook functions to push data to Editor-UI */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** Returns hook functions to push data to Editor-UI */ | |
/** Add hook callbacks to push live updates to the frontend. */ |
} | ||
} | ||
|
||
addHook<Hook extends keyof RegisteredHooks>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion - In my mind, the hook is the spot in the lifecycle where we run one or more registered callbacks.
addHook<Hook extends keyof RegisteredHooks>( | |
addCallback<Hook extends keyof RegisteredHooks>( |
/** Returns hook functions to save workflow execution and call error workflow */ | ||
private addSavingHooks(hooks: ExecutionHooks, isWorker: boolean) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need much more work until hooks are organized in a way that makes sense, but until we get there maybe we can use more accurate names, even rather long.
/** Returns hook functions to save workflow execution and call error workflow */ | |
private addSavingHooks(hooks: ExecutionHooks, isWorker: boolean) { | |
private addWorkflowExecuteAfterCallback(hooks: ExecutionHooks, isWorker: boolean) { |
Summary
This PR
WorkflowHooks
toExecutionHooks
n8n-workflow
ton8n-core
ExecutionHooksFactory
class, and moves all execution hooks code out ofworkflow-execute-additional-data
Related Linear tickets, Github issues, and Community forum posts
Review / Merge checklist
release/backport
(if the PR is an urgent fix that needs to be backported)