'Test workflow' UI hangs on custom send and wait node, unless there's a base wait node present

‘Test workflow’ UI hangs on custom send and wait node, unless there’s a base wait node present

Hey all!

I’m making a custom ‘send and wait’ node modeled after the Slack and Gmail approval nodes. On execute, it constructs a callback/webhook url, sends a request to some other 3rd party http service, and puts execution to wait unlimited. On webhook (call made from 3rd party http service with constructed callback url), it sets the output to the payload body.

Given a very simple workflow of Trigger → SendAndWait → NoOp, using ‘Test workflow’ will lead execution to wait for a webhook callback on SendAndWait. When this call is made (even successfully), the UI does not display node output or resume execution to the next node.

Hitting stop at this point displays a message that the workflow already completed successfully, and at this point I can inspect the SendAndWait output here or in historical executions.

However, if I place a normal wait node in parallel, e.g. Trigger → [SendAndWait, Wait] → NoOp, then output will display immediately on the SendAndWait node after receiving it, and execution will move to the Wait node to hold for its own webhook.

Ultimately would like to figure out how to fix UI updates during ‘Test webhook’ to better develop workflows with my custom SendAndWait nodes.

Thank you!

What is the error message (if any)?

None

Information on your n8n setup

  • n8n version: latest
  • Database (default: SQLite): postgres
  • n8n EXECUTIONS_PROCESS setting (default: own, main): own
  • Running n8n via (Docker, npm, n8n cloud, desktop app): docker compose
  • Operating system: Windows
1 Like

Hey @wumphlett

Welcome to the community :+1:

This actually sounds like a bug we fixed recently when implementing the multistep form nodes. Can you try updating n8n and seeing if the issue is still there?

Hey @Jon, thanks for the welcome!

The behavior has changed but its still not working as inspected

Now, instead of spinning on the SendAndWait node, execution flow will continue to the next node, and then it will spin and wait infinitely on that next node, even if its not a webhook node.

Even though “execution flow” is moved on during Test workflow, no output shows up for the SendAndWait node itself, until I again stop the test and can inspect each node and its state.

I updated my base docker image tag to :next, looks like its on v1.68.0

Ah, just found my issue

I found the check to see if a node is a ‘send and wait’ node

It looks like you’re required to set your path to your node id which I had, but I missed creating a property named ‘operation’ set to SEND_AND_WAIT_OPERATION.

The simplest node I can write that correctly sends and waits is

import type {
	IExecuteFunctions,
	IHttpRequestOptions,
	INodeExecutionData,
	INodeType,
	INodeTypeDescription,
	IWebhookFunctions,
	IWebhookResponseData,
	JsonObject,
} from 'n8n-workflow';

import {
	NodeApiError,
	NodeConnectionType,
	SEND_AND_WAIT_OPERATION,
	WAIT_TIME_UNLIMITED,
} from 'n8n-workflow';

export class SendAndWait implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'Send And Wait',
		name: 'sendAndWait',
		icon: 'file:hourglass.svg',
		iconColor: 'blue',
		group: ['transform'],
		version: 1,
		description: 'Send And Wait',
		defaults: {
			name: 'Send And Wait',
		},
		inputs: [NodeConnectionType.Main],
		outputs: [NodeConnectionType.Main],
		webhooks: [
			{
				name: 'default',
				httpMethod: 'POST',
				responseMode: 'onReceived',
				responseData: '',
				path: '={{ $nodeId }}',
				restartWebhook: true,
				isFullPath: true,
			}
		],
		properties: [
			{
				displayName: 'Operation',
				name: 'operation',
				type: 'options',
				required: true,
				options: [
					{
						name: "Schedule",
						value: SEND_AND_WAIT_OPERATION
					},
				],
				default: SEND_AND_WAIT_OPERATION,
				noDataExpression: true,
			},
		],
	};

	async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
		const req = this.getRequestObject();

		return {
			webhookResponse: '{"message":"Workflow continued"}',
			workflowData: [[{ json: req.body }]],
		};
	}

	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
		const resumeUrl = this.evaluateExpression('{{ $execution?.resumeUrl }}', 0) as string;
		const nodeId = this.evaluateExpression('{{ $nodeId }}', 0) as string;

		let url = `${resumeUrl}/${nodeId}`;

		const options: IHttpRequestOptions = {
			headers: {
				'content-type': 'application/json',
			},
			method: 'POST',
			url: 'http://my.api.com/v1/foobar',
			body: {
				callback: url
			},
			json: true,
		};
		try {
			await this.helpers.httpRequest.call(this, options);
		} catch (error) {
			throw new NodeApiError(this.getNode(), error as JsonObject);
		}

		await this.putExecutionToWait(new Date(WAIT_TIME_UNLIMITED));
		return [this.getInputData()];
	}
}

Do you know if there’s any plan in the future to support a send and wait pattern without requiring ‘magic’ settings?

Thank you for the help!

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.