mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-09 11:57:28 -08:00
c8d322a9ba
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
import { Service } from 'typedi';
|
|
import { CacheService } from '@/services/cache/cache.service';
|
|
import type { IWebhookData } from 'n8n-workflow';
|
|
import type { IWorkflowDb } from '@/Interfaces';
|
|
import { TEST_WEBHOOK_TIMEOUT, TEST_WEBHOOK_TIMEOUT_BUFFER } from '@/constants';
|
|
import { OrchestrationService } from '@/services/orchestration.service';
|
|
|
|
export type TestWebhookRegistration = {
|
|
pushRef?: string;
|
|
workflowEntity: IWorkflowDb;
|
|
destinationNode?: string;
|
|
webhook: IWebhookData;
|
|
};
|
|
|
|
@Service()
|
|
export class TestWebhookRegistrationsService {
|
|
constructor(
|
|
private readonly cacheService: CacheService,
|
|
private readonly orchestrationService: OrchestrationService,
|
|
) {}
|
|
|
|
private readonly cacheKey = 'test-webhooks';
|
|
|
|
async register(registration: TestWebhookRegistration) {
|
|
const hashKey = this.toKey(registration.webhook);
|
|
|
|
await this.cacheService.setHash(this.cacheKey, { [hashKey]: registration });
|
|
|
|
if (!this.orchestrationService.isMultiMainSetupEnabled) return;
|
|
|
|
/**
|
|
* 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.
|
|
* We set a TTL on the key so that it is cleared even on creator process crash,
|
|
* with an additional buffer to ensure this safeguard expiration will not delete
|
|
* the key before the regular test webhook timeout fetches the key to delete it.
|
|
*/
|
|
const ttl = TEST_WEBHOOK_TIMEOUT + TEST_WEBHOOK_TIMEOUT_BUFFER;
|
|
|
|
await this.cacheService.expire(this.cacheKey, ttl);
|
|
}
|
|
|
|
async deregister(arg: IWebhookData | string) {
|
|
if (typeof arg === 'string') {
|
|
await this.cacheService.deleteFromHash(this.cacheKey, arg);
|
|
} else {
|
|
const hashKey = this.toKey(arg);
|
|
await this.cacheService.deleteFromHash(this.cacheKey, hashKey);
|
|
}
|
|
}
|
|
|
|
async get(key: string) {
|
|
return await this.cacheService.getHashValue<TestWebhookRegistration>(this.cacheKey, key);
|
|
}
|
|
|
|
async getAllKeys() {
|
|
const hash = await this.cacheService.getHash<TestWebhookRegistration>(this.cacheKey);
|
|
|
|
if (!hash) return [];
|
|
|
|
return Object.keys(hash);
|
|
}
|
|
|
|
async getAllRegistrations() {
|
|
const hash = await this.cacheService.getHash<TestWebhookRegistration>(this.cacheKey);
|
|
|
|
if (!hash) return [];
|
|
|
|
return Object.values(hash);
|
|
}
|
|
|
|
async deregisterAll() {
|
|
await this.cacheService.delete(this.cacheKey);
|
|
}
|
|
|
|
toKey(webhook: Pick<IWebhookData, 'webhookId' | 'httpMethod' | 'path'>) {
|
|
const { webhookId, httpMethod, path: webhookPath } = webhook;
|
|
|
|
if (!webhookId) return [httpMethod, webhookPath].join('|');
|
|
|
|
let path = webhookPath;
|
|
|
|
if (path.startsWith(webhookId)) {
|
|
const cutFromIndex = path.indexOf('/') + 1;
|
|
|
|
path = path.slice(cutFromIndex);
|
|
}
|
|
|
|
return [httpMethod, webhookId, path.split('/').length].join('|');
|
|
}
|
|
}
|