2023-01-27 05:56:56 -08:00
|
|
|
import type express from 'express';
|
2024-09-12 09:07:18 -07:00
|
|
|
import * as NodeExecuteFunctions from 'n8n-core';
|
2024-01-11 05:01:07 -08:00
|
|
|
import { WebhookPathTakenError, Workflow } from 'n8n-workflow';
|
|
|
|
import type {
|
|
|
|
IWebhookData,
|
|
|
|
IWorkflowExecuteAdditionalData,
|
|
|
|
IHttpRequestMethods,
|
|
|
|
IRunData,
|
2019-06-23 03:35:23 -07:00
|
|
|
} from 'n8n-workflow';
|
2024-09-12 09:07:18 -07:00
|
|
|
import { Service } from 'typedi';
|
|
|
|
|
2024-01-12 02:48:58 -08:00
|
|
|
import { TEST_WEBHOOK_TIMEOUT } from '@/constants';
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
|
|
|
import { WebhookNotFoundError } from '@/errors/response-errors/webhook-not-found.error';
|
2024-09-12 09:07:18 -07:00
|
|
|
import { WorkflowMissingIdError } from '@/errors/workflow-missing-id.error';
|
|
|
|
import type { IWorkflowDb } from '@/interfaces';
|
|
|
|
import { NodeTypes } from '@/node-types';
|
|
|
|
import { Push } from '@/push';
|
2024-10-16 08:34:32 -07:00
|
|
|
import { Publisher } from '@/scaling/pubsub/publisher.service';
|
2024-09-12 09:07:18 -07:00
|
|
|
import { OrchestrationService } from '@/services/orchestration.service';
|
2024-08-07 01:23:44 -07:00
|
|
|
import { removeTrailingSlash } from '@/utils';
|
|
|
|
import type { TestWebhookRegistration } from '@/webhooks/test-webhook-registrations.service';
|
|
|
|
import { TestWebhookRegistrationsService } from '@/webhooks/test-webhook-registrations.service';
|
2024-09-12 09:07:18 -07:00
|
|
|
import * as WebhookHelpers from '@/webhooks/webhook-helpers';
|
2024-08-22 02:10:37 -07:00
|
|
|
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
2024-12-04 06:33:46 -08:00
|
|
|
import type { WorkflowRequest } from '@/workflows/workflow.request';
|
2024-09-12 09:07:18 -07:00
|
|
|
|
|
|
|
import type {
|
|
|
|
IWebhookResponseCallbackData,
|
|
|
|
IWebhookManager,
|
|
|
|
WebhookAccessControlOptions,
|
|
|
|
WebhookRequest,
|
|
|
|
} from './webhook.types';
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2024-08-07 01:23:44 -07:00
|
|
|
/**
|
|
|
|
* Service for handling the execution of webhooks of manual executions
|
|
|
|
* that use the [Test URL](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/#webhook-urls).
|
|
|
|
*/
|
2023-02-21 10:21:56 -08:00
|
|
|
@Service()
|
2023-08-01 08:32:30 -07:00
|
|
|
export class TestWebhooks implements IWebhookManager {
|
2023-07-28 09:28:17 -07:00
|
|
|
constructor(
|
2023-11-22 08:49:56 -08:00
|
|
|
private readonly push: Push,
|
|
|
|
private readonly nodeTypes: NodeTypes,
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
private readonly registrations: TestWebhookRegistrationsService,
|
2024-01-22 02:16:29 -08:00
|
|
|
private readonly orchestrationService: OrchestrationService,
|
2024-10-16 08:34:32 -07:00
|
|
|
private readonly publisher: Publisher,
|
2023-12-19 08:32:02 -08:00
|
|
|
) {}
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
private timeouts: { [webhookKey: string]: NodeJS.Timeout } = {};
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
/**
|
2023-12-28 00:28:12 -08:00
|
|
|
* Return a promise that resolves when the test webhook is called.
|
|
|
|
* Also inform the FE of the result and remove the test webhook.
|
2019-06-23 03:35:23 -07:00
|
|
|
*/
|
2023-08-01 08:32:30 -07:00
|
|
|
async executeWebhook(
|
|
|
|
request: WebhookRequest,
|
2019-06-23 03:35:23 -07:00
|
|
|
response: express.Response,
|
2024-08-07 01:23:44 -07:00
|
|
|
): Promise<IWebhookResponseCallbackData> {
|
2023-08-01 08:32:30 -07:00
|
|
|
const httpMethod = request.method;
|
2021-01-28 06:44:10 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
let path = removeTrailingSlash(request.params.path);
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-08-25 04:28:32 -07:00
|
|
|
request.params = {} as WebhookRequest['params'];
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
let webhook = await this.getActiveWebhook(httpMethod, path);
|
2021-02-09 00:14:40 -08:00
|
|
|
|
2023-12-19 08:32:02 -08:00
|
|
|
if (!webhook) {
|
|
|
|
// no static webhook, so check if dynamic
|
|
|
|
// e.g. `/webhook-test/<uuid>/user/:id/create`
|
2023-02-10 06:02:47 -08:00
|
|
|
|
2023-12-19 08:32:02 -08:00
|
|
|
const [webhookId, ...segments] = path.split('/');
|
2021-02-09 00:14:40 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
webhook = await this.getActiveWebhook(httpMethod, segments.join('/'), webhookId);
|
2023-07-31 02:00:48 -07:00
|
|
|
|
2023-12-19 08:32:02 -08:00
|
|
|
if (!webhook)
|
|
|
|
throw new WebhookNotFoundError({
|
|
|
|
path,
|
|
|
|
httpMethod,
|
|
|
|
webhookMethods: await this.getWebhookMethods(path),
|
|
|
|
});
|
2021-01-28 06:44:10 -08:00
|
|
|
|
2023-12-19 08:32:02 -08:00
|
|
|
path = webhook.path;
|
|
|
|
|
|
|
|
path.split('/').forEach((segment, index) => {
|
|
|
|
if (segment.startsWith(':')) {
|
|
|
|
request.params[segment.slice(1)] = segments[index];
|
2021-01-23 11:00:32 -08:00
|
|
|
}
|
|
|
|
});
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const key = this.registrations.toKey(webhook);
|
2020-01-22 15:06:43 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const registration = await this.registrations.get(key);
|
|
|
|
|
|
|
|
if (!registration) {
|
2023-12-19 08:32:02 -08:00
|
|
|
throw new WebhookNotFoundError({
|
|
|
|
path,
|
|
|
|
httpMethod,
|
|
|
|
webhookMethods: await this.getWebhookMethods(path),
|
|
|
|
});
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
}
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2024-04-03 04:43:14 -07:00
|
|
|
const { destinationNode, pushRef, workflowEntity, webhook: testWebhook } = registration;
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
|
|
|
|
const workflow = this.toWorkflow(workflowEntity);
|
2020-01-22 15:06:43 -08:00
|
|
|
|
2024-02-01 09:05:23 -08:00
|
|
|
if (testWebhook.staticData) workflow.setTestStaticData(testWebhook.staticData);
|
|
|
|
|
2023-12-19 08:32:02 -08:00
|
|
|
const workflowStartNode = workflow.getNode(webhook.node);
|
2023-12-28 00:28:12 -08:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
if (workflowStartNode === null) {
|
2023-11-28 01:19:27 -08:00
|
|
|
throw new NotFoundError('Could not find node to process webhook.');
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
2024-01-17 07:08:50 -08:00
|
|
|
return await new Promise(async (resolve, reject) => {
|
2019-06-23 03:35:23 -07:00
|
|
|
try {
|
|
|
|
const executionMode = 'manual';
|
2021-08-21 05:11:32 -07:00
|
|
|
const executionId = await WebhookHelpers.executeWebhook(
|
|
|
|
workflow,
|
2024-03-26 06:22:57 -07:00
|
|
|
webhook,
|
2023-12-19 08:32:02 -08:00
|
|
|
workflowEntity,
|
2021-08-21 05:11:32 -07:00
|
|
|
workflowStartNode,
|
|
|
|
executionMode,
|
2024-04-03 04:43:14 -07:00
|
|
|
pushRef,
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
undefined, // IRunExecutionData
|
|
|
|
undefined, // executionId
|
2021-08-21 05:11:32 -07:00
|
|
|
request,
|
|
|
|
response,
|
2024-08-07 01:23:44 -07:00
|
|
|
(error: Error | null, data: IWebhookResponseCallbackData) => {
|
2023-02-10 06:02:47 -08:00
|
|
|
if (error !== null) reject(error);
|
|
|
|
else resolve(data);
|
2019-06-23 03:35:23 -07:00
|
|
|
},
|
2023-02-10 06:02:47 -08:00
|
|
|
destinationNode,
|
2019-06-23 03:35:23 -07:00
|
|
|
);
|
|
|
|
|
2023-02-10 06:02:47 -08:00
|
|
|
// The workflow did not run as the request was probably setup related
|
|
|
|
// or a ping so do not resolve the promise and wait for the real webhook
|
|
|
|
// request instead.
|
|
|
|
if (executionId === undefined) return;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
// Inform editor-ui that webhook got received
|
2024-04-03 04:43:14 -07:00
|
|
|
if (pushRef !== undefined) {
|
2023-12-19 08:32:02 -08:00
|
|
|
this.push.send(
|
|
|
|
'testWebhookReceived',
|
|
|
|
{ workflowId: webhook?.workflowId, executionId },
|
2024-04-03 04:43:14 -07:00
|
|
|
pushRef,
|
2023-12-19 08:32:02 -08:00
|
|
|
);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
2023-02-13 07:16:53 -08:00
|
|
|
} catch {}
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2024-01-12 02:48:58 -08:00
|
|
|
/**
|
|
|
|
* Multi-main setup: In a manual webhook execution, the main process that
|
|
|
|
* handles a webhook might not be the same as the main process that created
|
|
|
|
* the webhook. If so, after the test webhook has been successfully executed,
|
|
|
|
* the handler process commands the creator process to clear its test webhooks.
|
|
|
|
*/
|
|
|
|
if (
|
2024-01-22 02:16:29 -08:00
|
|
|
this.orchestrationService.isMultiMainSetupEnabled &&
|
2024-04-03 04:43:14 -07:00
|
|
|
pushRef &&
|
|
|
|
!this.push.getBackend().hasPushRef(pushRef)
|
2024-01-12 02:48:58 -08:00
|
|
|
) {
|
2024-10-16 08:34:32 -07:00
|
|
|
void this.publisher.publishCommand({
|
|
|
|
command: 'clear-test-webhooks',
|
|
|
|
payload: { webhookKey: key, workflowEntity, pushRef },
|
|
|
|
});
|
2024-01-12 02:48:58 -08:00
|
|
|
return;
|
|
|
|
}
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
|
2024-01-12 02:48:58 -08:00
|
|
|
this.clearTimeout(key);
|
2023-02-13 07:16:53 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
await this.deactivateWebhooks(workflow);
|
2019-06-23 03:35:23 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-01-12 02:48:58 -08:00
|
|
|
clearTimeout(key: string) {
|
|
|
|
const timeout = this.timeouts[key];
|
|
|
|
|
|
|
|
if (timeout) clearTimeout(timeout);
|
|
|
|
}
|
|
|
|
|
2023-12-19 08:32:02 -08:00
|
|
|
async getWebhookMethods(path: string) {
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const allKeys = await this.registrations.getAllKeys();
|
|
|
|
|
|
|
|
const webhookMethods = allKeys
|
2023-12-19 08:32:02 -08:00
|
|
|
.filter((key) => key.includes(path))
|
|
|
|
.map((key) => key.split('|')[0] as IHttpRequestMethods);
|
|
|
|
|
|
|
|
if (!webhookMethods.length) throw new WebhookNotFoundError({ path });
|
2020-07-24 07:24:18 -07:00
|
|
|
|
|
|
|
return webhookMethods;
|
|
|
|
}
|
|
|
|
|
2023-11-22 08:49:56 -08:00
|
|
|
async findAccessControlOptions(path: string, httpMethod: IHttpRequestMethods) {
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const allKeys = await this.registrations.getAllKeys();
|
|
|
|
|
|
|
|
const webhookKey = allKeys.find((key) => key.includes(path) && key.startsWith(httpMethod));
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-11-22 08:49:56 -08:00
|
|
|
if (!webhookKey) return;
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const registration = await this.registrations.get(webhookKey);
|
|
|
|
|
|
|
|
if (!registration) return;
|
|
|
|
|
|
|
|
const { workflowEntity } = registration;
|
|
|
|
|
|
|
|
const workflow = this.toWorkflow(workflowEntity);
|
|
|
|
|
2023-11-22 08:49:56 -08:00
|
|
|
const webhookNode = Object.values(workflow.nodes).find(
|
|
|
|
({ type, parameters, typeVersion }) =>
|
|
|
|
parameters?.path === path &&
|
|
|
|
(parameters?.httpMethod ?? 'GET') === httpMethod &&
|
|
|
|
'webhook' in this.nodeTypes.getByNameAndVersion(type, typeVersion),
|
|
|
|
);
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-11-22 08:49:56 -08:00
|
|
|
return webhookNode?.parameters?.options as WebhookAccessControlOptions;
|
|
|
|
}
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
/**
|
|
|
|
* Return whether activating a workflow requires listening for webhook calls.
|
|
|
|
* For every webhook call to listen for, also activate the webhook.
|
|
|
|
*/
|
2024-12-04 06:33:46 -08:00
|
|
|
async needsWebhook(options: {
|
|
|
|
userId: string;
|
|
|
|
workflowEntity: IWorkflowDb;
|
|
|
|
additionalData: IWorkflowExecuteAdditionalData;
|
|
|
|
runData?: IRunData;
|
|
|
|
pushRef?: string;
|
|
|
|
destinationNode?: string;
|
|
|
|
triggerToStartFrom?: WorkflowRequest.ManualRunPayload['triggerToStartFrom'];
|
|
|
|
}) {
|
|
|
|
const {
|
|
|
|
userId,
|
|
|
|
workflowEntity,
|
|
|
|
additionalData,
|
|
|
|
runData,
|
|
|
|
pushRef,
|
|
|
|
destinationNode,
|
|
|
|
triggerToStartFrom,
|
|
|
|
} = options;
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
if (!workflowEntity.id) throw new WorkflowMissingIdError(workflowEntity);
|
|
|
|
|
|
|
|
const workflow = this.toWorkflow(workflowEntity);
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2024-12-04 06:33:46 -08:00
|
|
|
let webhooks = WebhookHelpers.getWorkflowWebhooks(
|
2021-08-21 05:11:32 -07:00
|
|
|
workflow,
|
|
|
|
additionalData,
|
|
|
|
destinationNode,
|
|
|
|
true,
|
|
|
|
);
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2024-12-04 06:33:46 -08:00
|
|
|
// If we have a preferred trigger with data, we don't have to listen for a
|
|
|
|
// webhook.
|
|
|
|
if (triggerToStartFrom?.data) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have a preferred trigger without data we only want to listen for
|
|
|
|
// that trigger, not the other ones.
|
|
|
|
if (triggerToStartFrom) {
|
|
|
|
webhooks = webhooks.filter((w) => w.node === triggerToStartFrom.name);
|
|
|
|
}
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
if (!webhooks.some((w) => w.webhookDescription.restartWebhook !== true)) {
|
2023-12-19 08:32:02 -08:00
|
|
|
return false; // no webhooks found to start a workflow
|
2020-05-03 08:55:14 -07:00
|
|
|
}
|
|
|
|
|
2024-01-17 07:08:50 -08:00
|
|
|
const timeout = setTimeout(
|
|
|
|
async () => await this.cancelWebhook(workflow.id),
|
|
|
|
TEST_WEBHOOK_TIMEOUT,
|
|
|
|
);
|
2023-02-10 06:02:47 -08:00
|
|
|
|
2023-12-19 08:32:02 -08:00
|
|
|
for (const webhook of webhooks) {
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const key = this.registrations.toKey(webhook);
|
2024-04-23 22:46:16 -07:00
|
|
|
const registrationByKey = await this.registrations.get(key);
|
2023-12-28 00:28:12 -08:00
|
|
|
|
2024-01-11 05:01:07 -08:00
|
|
|
if (runData && webhook.node in runData) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-04-23 22:46:16 -07:00
|
|
|
// if registration already exists and is not a test webhook created by this user in this workflow throw an error
|
|
|
|
if (
|
|
|
|
registrationByKey &&
|
|
|
|
!webhook.webhookId &&
|
|
|
|
!registrationByKey.webhook.isTest &&
|
|
|
|
registrationByKey.webhook.userId !== userId &&
|
|
|
|
registrationByKey.webhook.workflowId !== workflow.id
|
|
|
|
) {
|
2023-12-28 00:28:12 -08:00
|
|
|
throw new WebhookPathTakenError(webhook.node);
|
|
|
|
}
|
2023-07-31 02:00:48 -07:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
webhook.path = removeTrailingSlash(webhook.path);
|
|
|
|
webhook.isTest = true;
|
2020-05-30 16:03:58 -07:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
/**
|
2024-01-09 07:02:32 -08:00
|
|
|
* Additional data cannot be cached because of circular refs.
|
|
|
|
* Hence store the `userId` and recreate additional data when needed.
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
*/
|
2024-01-09 07:02:32 -08:00
|
|
|
const { workflowExecuteAdditionalData: _, ...cacheableWebhook } = webhook;
|
|
|
|
|
|
|
|
cacheableWebhook.userId = userId;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2024-01-16 00:17:41 -08:00
|
|
|
const registration: TestWebhookRegistration = {
|
2024-04-03 04:43:14 -07:00
|
|
|
pushRef,
|
2024-01-16 00:17:41 -08:00
|
|
|
workflowEntity,
|
|
|
|
destinationNode,
|
|
|
|
webhook: cacheableWebhook as IWebhookData,
|
|
|
|
};
|
|
|
|
|
2020-10-21 08:50:23 -07:00
|
|
|
try {
|
2024-01-16 00:17:41 -08:00
|
|
|
/**
|
|
|
|
* Register the test webhook _before_ creation at third-party service
|
|
|
|
* in case service sends a confirmation request immediately on creation.
|
|
|
|
*/
|
|
|
|
await this.registrations.register(registration);
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
await workflow.createWebhookIfNotExists(webhook, NodeExecuteFunctions, 'manual', 'manual');
|
|
|
|
|
2024-01-09 07:02:32 -08:00
|
|
|
cacheableWebhook.staticData = workflow.staticData;
|
|
|
|
|
2024-01-16 00:17:41 -08:00
|
|
|
await this.registrations.register(registration);
|
2023-12-19 08:32:02 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
this.timeouts[key] = timeout;
|
|
|
|
} catch (error) {
|
2023-12-28 00:28:12 -08:00
|
|
|
await this.deactivateWebhooks(workflow);
|
2023-07-31 02:00:48 -07:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
delete this.timeouts[key];
|
|
|
|
|
2020-10-21 08:50:23 -07:00
|
|
|
throw error;
|
|
|
|
}
|
2020-03-20 16:30:03 -07:00
|
|
|
}
|
2020-01-22 15:06:43 -08:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
async cancelWebhook(workflowId: string) {
|
2019-06-23 03:35:23 -07:00
|
|
|
let foundWebhook = false;
|
2023-07-31 02:00:48 -07:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const allWebhookKeys = await this.registrations.getAllKeys();
|
|
|
|
|
|
|
|
for (const key of allWebhookKeys) {
|
|
|
|
const registration = await this.registrations.get(key);
|
|
|
|
|
|
|
|
if (!registration) continue;
|
|
|
|
|
2024-04-03 04:43:14 -07:00
|
|
|
const { pushRef, workflowEntity } = registration;
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
|
|
|
|
const workflow = this.toWorkflow(workflowEntity);
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2023-12-19 08:32:02 -08:00
|
|
|
if (workflowEntity.id !== workflowId) continue;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2024-01-12 02:48:58 -08:00
|
|
|
this.clearTimeout(key);
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2024-04-03 04:43:14 -07:00
|
|
|
if (pushRef !== undefined) {
|
2019-06-23 03:35:23 -07:00
|
|
|
try {
|
2024-04-03 04:43:14 -07:00
|
|
|
this.push.send('testWebhookDeleted', { workflowId }, pushRef);
|
2023-02-10 06:02:47 -08:00
|
|
|
} catch {
|
2022-09-02 07:13:17 -07:00
|
|
|
// Could not inform editor, probably is not connected anymore. So simply go on.
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 08:50:23 -07:00
|
|
|
if (!foundWebhook) {
|
|
|
|
// As it removes all webhooks of the workflow execute only once
|
2023-12-28 00:28:12 -08:00
|
|
|
void this.deactivateWebhooks(workflow);
|
2020-10-21 08:50:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
foundWebhook = true;
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return foundWebhook;
|
|
|
|
}
|
2023-12-19 08:32:02 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
async getActiveWebhook(httpMethod: IHttpRequestMethods, path: string, webhookId?: string) {
|
|
|
|
const key = this.registrations.toKey({ httpMethod, path, webhookId });
|
2023-12-19 08:32:02 -08:00
|
|
|
|
|
|
|
let webhook: IWebhookData | undefined;
|
|
|
|
let maxMatches = 0;
|
|
|
|
const pathElementsSet = new Set(path.split('/'));
|
|
|
|
// check if static elements match in path
|
|
|
|
// if more results have been returned choose the one with the most static-route matches
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const registration = await this.registrations.get(key);
|
|
|
|
|
|
|
|
if (!registration) return;
|
|
|
|
|
|
|
|
const { webhook: dynamicWebhook } = registration;
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
const staticElements = dynamicWebhook.path.split('/').filter((ele) => !ele.startsWith(':'));
|
|
|
|
const allStaticExist = staticElements.every((staticEle) => pathElementsSet.has(staticEle));
|
|
|
|
|
|
|
|
if (allStaticExist && staticElements.length > maxMatches) {
|
|
|
|
maxMatches = staticElements.length;
|
|
|
|
webhook = dynamicWebhook;
|
|
|
|
}
|
|
|
|
// handle routes with no static elements
|
|
|
|
else if (staticElements.length === 0 && !webhook) {
|
|
|
|
webhook = dynamicWebhook;
|
|
|
|
}
|
2023-12-19 08:32:02 -08:00
|
|
|
|
|
|
|
return webhook;
|
|
|
|
}
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
/**
|
|
|
|
* Deactivate all registered test webhooks of a workflow.
|
|
|
|
*/
|
|
|
|
async deactivateWebhooks(workflow: Workflow) {
|
|
|
|
const allRegistrations = await this.registrations.getAllRegistrations();
|
2023-12-28 00:28:12 -08:00
|
|
|
|
perf(core): Improve caching service (#8213)
Story: https://linear.app/n8n/issue/PAY-1188
- Implement Redis hashes on the caching service, based on Micha's work
in #7747, adapted from `node-cache-manager-ioredis-yet`. Optimize
workflow ownership lookups and manual webhook lookups with Redis hashes.
- Simplify the caching service by removing all currently unused methods
and options: `enable`, `disable`, `getCache`, `keys`, `keyValues`,
`refreshFunctionEach`, `refreshFunctionMany`, `refreshTtl`, etc.
- Remove the flag `N8N_CACHE_ENABLED`. Currently some features on
`master` are broken with caching disabled, and test webhooks now rely
entirely on caching, for multi-main setup support. We originally
introduced this flag to protect against excessive memory usage, but
total cache usage is low enough that we decided to drop this setting.
Apparently this flag was also never documented.
- Overall caching service refactor: use generics, reduce branching, add
discriminants for cache kinds for better type safety, type caching
events, improve readability, remove outdated docs, etc. Also refactor
and expand caching service tests.
Follow-up to: https://github.com/n8n-io/n8n/pull/8176
---------
Co-authored-by: Michael Auerswald <michael.auerswald@gmail.com>
2024-01-05 02:52:44 -08:00
|
|
|
if (!allRegistrations.length) return; // nothing to deactivate
|
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
type WebhooksByWorkflow = { [workflowId: string]: IWebhookData[] };
|
2023-12-19 08:32:02 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const webhooksByWorkflow = allRegistrations.reduce<WebhooksByWorkflow>((acc, cur) => {
|
|
|
|
const { workflowId } = cur.webhook;
|
2023-12-19 08:32:02 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
acc[workflowId] ||= [];
|
|
|
|
acc[workflowId].push(cur.webhook);
|
2023-12-19 08:32:02 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
return acc;
|
|
|
|
}, {});
|
2023-12-19 08:32:02 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
const webhooks = webhooksByWorkflow[workflow.id];
|
2023-12-19 08:32:02 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
if (!webhooks) return; // nothing to deactivate
|
2023-12-19 08:32:02 -08:00
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
for (const webhook of webhooks) {
|
2024-01-09 07:02:32 -08:00
|
|
|
const { userId, staticData } = webhook;
|
|
|
|
|
|
|
|
if (userId) {
|
|
|
|
webhook.workflowExecuteAdditionalData = await WorkflowExecuteAdditionalData.getBase(userId);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (staticData) workflow.staticData = staticData;
|
|
|
|
|
2023-12-28 00:28:12 -08:00
|
|
|
await workflow.deleteWebhook(webhook, NodeExecuteFunctions, 'internal', 'update');
|
|
|
|
}
|
2024-01-12 02:48:58 -08:00
|
|
|
|
|
|
|
await this.registrations.deregisterAll();
|
2023-12-28 00:28:12 -08:00
|
|
|
}
|
2023-12-19 08:32:02 -08:00
|
|
|
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
/**
|
2024-01-12 02:48:58 -08:00
|
|
|
* Convert a `WorkflowEntity` from `typeorm` to a temporary `Workflow` from `n8n-workflow`.
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
*/
|
2024-01-09 07:02:32 -08:00
|
|
|
toWorkflow(workflowEntity: IWorkflowDb) {
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
return new Workflow({
|
|
|
|
id: workflowEntity.id,
|
|
|
|
name: workflowEntity.name,
|
|
|
|
nodes: workflowEntity.nodes,
|
|
|
|
connections: workflowEntity.connections,
|
|
|
|
active: false,
|
|
|
|
nodeTypes: this.nodeTypes,
|
2024-02-01 09:05:23 -08:00
|
|
|
staticData: {},
|
feat(core): Cache test webhook registrations (#8176)
In a multi-main setup, we have the following issue. The user's client
connects to main A and runs a test webhook, so main A starts listening
for a webhook call. A third-party service sends a request to the test
webhook URL. The request is forwarded by the load balancer to main B,
who is not listening for this webhook call. Therefore, the webhook call
is unhandled.
To start addressing this, cache test webhook registrations, using Redis
for queue mode and in-memory for regular mode. When the third-party
service sends a request to the test webhook URL, the request is
forwarded by the load balancer to main B, who fetches test webhooks from
the cache and, if it finds a match, executes the test webhook. This
should be transparent - test webhook behavior should remain the same as
so far.
Notes:
- Test webhook timeouts are not cached. A timeout is only relevant to
the process it was created in, so another process retrieving from Redis
a "foreign" timeout will be unable to act on it. A timeout also has
circular references, so `cache-manager-ioredis-yet` is unable to
serialize it.
- In a single-main scenario, the timeout remains in the single process
and is cleared on test webhook expiration, successful execution, and
manual cancellation - all as usual.
- In a multi-main scenario, we will need to have the process who
received the webhook call send a message to the process who created the
webhook directing this originating process to clear the timeout. This
will likely be implemented via execution lifecycle hooks and Redis
channel messages checking session ID. This implementation is out of
scope for this PR and will come next.
- Additional data in test webhooks is not cached. From what I can tell,
additional data is not needed for test webhooks to be executed.
Additional data also has circular references, so
`cache-manager-ioredis-yet` is unable to serialize it.
Follow-up to: #8155
2024-01-03 07:58:33 -08:00
|
|
|
settings: workflowEntity.settings,
|
|
|
|
});
|
2023-12-19 08:32:02 -08:00
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|