Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Wait Node): seconds timeout is unavailable when resume wait node … #13857

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions packages/nodes-base/nodes/Wait/Wait.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,11 @@ const onWebhookCallProperties = updateDisplayOptions(displayOnWebhook, [
]);

const webhookPath = '={{$parameter["options"]["webhookSuffix"] || ""}}';
/**
* If wait time is shorter than 65 seconds leave execution active because
we just check the database every 60 seconds.
*/
const SHORT_WAIT_THRESHOLD = 65 * 1000;

export class Wait extends Webhook {
authPropertyName = 'incomingAuthentication';
Expand Down Expand Up @@ -504,7 +509,7 @@ export class Wait extends Webhook {

// Timezone does not change relative dates, since they are just
// a number of seconds added to the current timestamp
waitTill = new Date(new Date().getTime() + waitAmount);
waitTill = new Date(Date.now() + waitAmount);
} else {
const dateTimeStr = context.getNodeParameter('dateTime', 0) as string;

Expand All @@ -522,15 +527,9 @@ export class Wait extends Webhook {
.toJSDate();
}

const waitValue = Math.max(waitTill.getTime() - new Date().getTime(), 0);

if (waitValue < 65000) {
// If wait time is shorter than 65 seconds leave execution active because
// we just check the database every 60 seconds.
return await new Promise((resolve) => {
const timer = setTimeout(() => resolve([context.getInputData()]), waitValue);
context.onExecutionCancellation(() => clearTimeout(timer));
});
const executionData = await this.generateShortWaitExecutionData(context, waitTill);
if (executionData) {
return executionData;
}

// If longer than 65 seconds put execution to wait
Expand Down Expand Up @@ -559,10 +558,15 @@ export class Wait extends Webhook {
}

waitAmount *= 1000;
waitTill = new Date(new Date().getTime() + waitAmount);
waitTill = new Date(Date.now() + waitAmount);
} else {
waitTill = new Date(context.getNodeParameter('maxDateAndTime', 0) as string);
}

const executionData = await this.generateShortWaitExecutionData(context, waitTill);
if (executionData) {
return executionData;
}
}

return await this.putToWait(context, waitTill);
Expand All @@ -572,4 +576,20 @@ export class Wait extends Webhook {
await context.putExecutionToWait(waitTill);
return [context.getInputData()];
}

private async generateShortWaitExecutionData(
context: IExecuteFunctions,
waitTill: Date,
): Promise<INodeExecutionData[][] | null> {
const waitValue = Math.max(waitTill.getTime() - Date.now(), 0);

if (waitValue >= SHORT_WAIT_THRESHOLD) {
return null;
}

return new Promise<INodeExecutionData[][]>((resolve) => {
const timer = setTimeout(() => resolve([context.getInputData()]), waitValue);
context.onExecutionCancellation(() => clearTimeout(timer));
});
}
}
295 changes: 295 additions & 0 deletions packages/nodes-base/nodes/Wait/test/Wait.webhook.workflow.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
{
"name": "[Unit Test] Wait Node - Webhook",
"nodes": [
{
"parameters": {},
"id": "ec0cce37-e0a4-42f6-ab9a-10412dccecbf",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [-460, 340]
},
{
"parameters": {
"value": "={{ $now }}",
"dataPropertyName": "afterTimestamp",
"toFormat": "X",
"options": {}
},
"id": "879a37e1-01b2-4347-b7b2-029ce24c248e",
"name": "After1",
"type": "n8n-nodes-base.dateTime",
"typeVersion": 1,
"position": [200, 240]
},
{
"parameters": {
"value": "={{ $now }}",
"dataPropertyName": "startTimestamp",
"toFormat": "X",
"options": {}
},
"id": "74f5b014-b0a0-4d14-b3e1-862b4e6a8050",
"name": "Before1",
"type": "n8n-nodes-base.dateTime",
"typeVersion": 1,
"position": [-200, 240]
},
{
"parameters": {},
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [700, 340],
"id": "a1c7c7db-9336-4712-a8c4-8eb2d1055eee",
"name": "Merge"
},
{
"parameters": {
"resume": "webhook",
"limitWaitTime": true,
"resumeAmount": 7,
"resumeUnit": "seconds",
"options": {}
},
"id": "b9cf3cd6-a365-4894-835d-8d7f442a78b7",
"name": "Wait on Webhook Call",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [0, 240],
"webhookId": "35edc971-c3e4-48cf-835d-4d73a4fd1fd8",
"notesInFlow": true,
"notes": "7s timeout"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ parseInt($json.afterTimestamp) }}",
"operation": "largerEqual",
"value2": "={{ parseInt($json.startTimestamp) + 7 }}"
}
]
}
},
"id": "d3ad2c95-1f13-4534-81dd-5f6c94e8061c",
"name": "Check",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [400, 240],
"notesInFlow": true,
"notes": "check if timeout after 7s"
},
{
"parameters": {
"keepOnlySet": true,
"values": {
"boolean": [
{
"name": "success",
"value": true
}
]
},
"options": {}
},
"id": "78d50315-05df-4277-9792-b46881c55b5f",
"name": "Set",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [900, 340],
"notesInFlow": true,
"notes": "success"
},
{
"parameters": {
"value": "={{ $now }}",
"dataPropertyName": "afterTimestamp",
"toFormat": "X",
"options": {}
},
"id": "68f750d4-9f98-48f5-ad9f-3a263a895299",
"name": "After2",
"type": "n8n-nodes-base.dateTime",
"typeVersion": 1,
"position": [200, 460]
},
{
"parameters": {
"value": "={{ $now }}",
"dataPropertyName": "startTimestamp",
"toFormat": "X",
"options": {}
},
"id": "7731f422-a903-47c9-ac8e-3a0055f1c9ca",
"name": "Before2",
"type": "n8n-nodes-base.dateTime",
"typeVersion": 1,
"position": [-200, 460]
},
{
"parameters": {
"resume": "webhook",
"limitWaitTime": true,
"resumeAmount": 67,
"resumeUnit": "seconds",
"options": {}
},
"id": "312d3b18-129e-4b90-8440-8ee0ec463aa5",
"name": "Wait on Webhook Call1",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [0, 460],
"webhookId": "35edc971-c3e4-48cf-835d-4d73a4fd1fd8",
"notesInFlow": true,
"notes": "67s timeout (for putExecutionToWait)"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ parseInt($json.afterTimestamp) }}",
"operation": "largerEqual",
"value2": "={{ parseInt($json.startTimestamp) + 67 }}"
}
]
}
},
"id": "851e91a5-b9f4-496d-aa43-d8b7799aa764",
"name": "Check1",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [400, 460],
"notesInFlow": true,
"notes": "check if timeout after 67s"
}
],
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Before1",
"type": "main",
"index": 0
},
{
"node": "Before2",
"type": "main",
"index": 0
}
]
]
},
"After1": {
"main": [
[
{
"node": "Check",
"type": "main",
"index": 0
}
]
]
},
"Before1": {
"main": [
[
{
"node": "Wait on Webhook Call",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Set",
"type": "main",
"index": 0
}
]
]
},
"Wait on Webhook Call": {
"main": [
[
{
"node": "After1",
"type": "main",
"index": 0
}
]
]
},
"Check": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"After2": {
"main": [
[
{
"node": "Check1",
"type": "main",
"index": 0
}
]
]
},
"Before2": {
"main": [
[
{
"node": "Wait on Webhook Call1",
"type": "main",
"index": 0
}
]
]
},
"Wait on Webhook Call1": {
"main": [
[
{
"node": "After2",
"type": "main",
"index": 0
}
]
]
},
"Check1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
}
},
"pinData": {
"Set": [
{
"success": true
}
]
},
"meta": {
"instanceId": "8a0f4e2702f32f19e733825a1554a3e8f324c0954c0f1d18c22769193f2baae3"
}
}