Building custom node - node doesn't wait for function to fully execute

Describe the issue/error/question

I have an issue that I am trying to build a custom node to query a Presto/Trino database. I am using an external package, and when I try to run a query with this package it works as expected. However, when I put it in an execute function within a Trino node, it does not.

To give you an idea, here is the package just as a plain js file, which works as expected (apologies but you need a Trino instance to run this, but I am hoping someone can still help me with what the difference is between a pure JS implementation vs an n8n node even without running the code):

import { Trino as TrinoClient } from 'trino-ts'

let updatesNotification = (response) => {
    console.log('update', response)
}

let errorNotification = (error) => {
    console.log('error', error)
}

let query = 'SELECT * FROM example_table'

const trino = new TrinoClient({
    catalog: 'xxx',
    schema: 'xxx',
    user: '[email protected]',
    password: 'xxx',
    host: 'xxx',
    port: xxx,
    source: 'NodeJS Trino Connector',
    checkStatusInterval: 1000, //1s
    isBasicAuth: true,
    isHttps: true,
    query: query,
    errorNotification,
    updatesNotification
})

const res = trino.go()

console.log('res', res)

If I run this, the updatesNotification function gets called multiple times, as expected, until the query finishes, when I get my result.

I tried to implement this within N8N as a custom node (:

import {
    IExecuteFunctions,
} from 'n8n-core'

import {
    INodeType,
    INodeTypeDescription,
} from 'n8n-workflow'

import { Trino as TrinoClient, TrinoResponse } from 'trino-ts'

export class Trino implements INodeType {
    description: INodeTypeDescription = {
        displayName: 'Trino / Presto Client',
        name: 'trino',
        icon: 'file:friendGrid.svg',
        group: ['transform'],
        version: 1,
        description: 'Query data from Trino SQL',
        defaults: {
            name: 'Trino',
        },
        inputs: ['main'],
        outputs: ['main'],
        credentials: [
            {
                name: 'trino',
                required: true,
                testedBy: 'trinoCredentialTest'
            },
        ],
        properties: [
            {
                displayName: 'Operation',
                name: 'operation',
                type: 'options',
                options: [
                    {
                        name: 'Execute Query',
                        value: 'executeQuery',
                        description: 'Execute an SQL query',
                        action: 'Execute a SQL query',
                    },
                ],
                default: 'executeQuery',
                noDataExpression: true,
            },
            {
                displayName: 'Query',
                name: 'query',
                type: 'string',
                displayOptions: {
                    show: {
                        operation: ['executeQuery'],
                    },
                },
                default: '',
                placeholder: 'SELECT id, name FROM product WHERE id < 40',
                required: true,
                description: 'The SQL query to execute',
            },
        ],
    };

    async execute(this: IExecuteFunctions): Promise<any> {

        const credentials = await this.getCredentials('trino')

        const updatesNotification = (response: TrinoResponse) => {
            console.log('update', response)
        }

        const errorNotification = (error: Error) => {
            console.log('error', error)
        }

        const query = this.getNodeParameter('query', 0) as string;

        const trino = new TrinoClient({
            catalog: 'awscatalog',
            schema: 'bigdata_schema',
            user: credentials.user as string,
            password: credentials.password as string,
            host: credentials.host as string,
            port: credentials.port as number,
            source: 'NodeJS Trino Connector',
            checkStatusInterval: 1000, //1s
            isBasicAuth: true,
            isHttps: true,
            query: query,
            errorNotification,
            updatesNotification
        })

        const res = await trino.go();
        console.log('res', res) // this will be undefined
    }
}

What happens:

  • The updatesNotification function gets called once, and I see the query in a pending status.
  • Then the node execution finishes

Instead, what I expect is for the function to be called over and over until finish, just like if I don’t use n8n just nodeJS like the first example. Is there some special way I need to write my execute function so that it is aware that it has to wait? I’ve tried to check other nodes eg. MySQL but I couldn’t find much difference… it is also awaiting a function and when that executes, it will return the output data.

Any ideas appreciated, thank you in advance!!!

Information on your n8n setup

  • n8n version: 0.213.0
  • Database you’re using (default: SQLite): SQLite
  • Running n8n with the execution process [own(default), main]: own
  • Running n8n via [Docker, npm, n8n.cloud, desktop app]: npm

Hey @mako,

I have added this to my list of things to look into but I am not sure when I will get to it, My first thought is it is probably going to be a promises / async thing which always gives me a bit of a headache.

1 Like

Hi Jon, thanks so much! It’s not super urgent, really appreciate you taking the time to look at it!

1 Like

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