Timing functions in TypeScript repos for NodeJS such as setTimeout, setInterval, etc

I’m not sure how to import timing functions for node JS, for example, import { setInterval } from 'node:timers/promises'. I get a WebPack exception when I attempt to import. I had to write my own using async generators, which are below, in case there is no other workaround. Is there a built-in timing function for this? Is my assumptions about no read-after-write guarantees per the note in the code below correct?

//in my utils
export function delay(ms: number) {
    return new Promise<void>((resolve) => {
        const start = Date.now();
        const check = () => {
            if (Date.now() - start >= ms) {
                resolve();
            } else {
                Promise.resolve().then(check); // Schedule the next tick
            }
        };
        check();
    });
}

export async function* customTimer(interval: number, iterations: number) {
    let count = 0;

    while (count < iterations) {
        yield count;
        count++;
        await delay(interval); // Custom delay instead of setTimeout
    }
}

Usage:

import { customTimer } from "./utils";

// IMPORTANT: there are no strong read-after-write guarantees in Foundry!
// this means I have to wait a bit for edits to be applied
//Read this for more details: https://www.palantir.com/docs/foundry/functions/edits-overview#caveat-edits-and-object-search
        const machine = await new Promise<MachineExecutions>(async (resolve, reject) => {
            let count = 0;
            let machine = getMachineExecution(solution);
            const interval = 1000; // 1 second interval
            const iterations = 5; // Run 5 times
            const timer = customTimer(interval, iterations);

            // I have no idea why, but I can't import timing functions from node, so I wrote my own
            for await (const tick of timer) {
                console.log(`Tick ${tick + 1}`);
                console.log(new Date().getSeconds());
               // this function will use the ObjectSet API to perform a search
                machine = getMachineExecution(solution);
                if (machine) {
                    return resolve(machine)
                }
            }

            reject(new Error('Machine execution could not be retrieved after 10 seconds'));
        })

Another thing that is strange is the only reason I tried to import the timing functions is setTimeout was unavailable. However, it works fine when I’m not authoring a FoO, ie, I have a standard function declared outside the class functions decorated with @Function, etc. This really feels like a constraint the functions team is imposing and it should be removed ASAP if that is the case.

1 Like

In general, you cannot import Node.js APIs since Typescript functions are executed in a very basic isolated V8 runtime environment.

We actually do happen to proxy a setTimeout function within this isolated environment though, so you should be able use that within a for-loop like so:

for (let i = 0; i < iterations; i++) {
    // Your code here
    // @ts-ignore
    await new Promise(resolve => setTimeout(resolve,  interval));
}

Note that you need the @ts-ignore since we do not include a function declaration for setTimeout. You can also just add the declaration yourself if you need the typing:

declare function setTimeout(
    callback: (...args: any[]) => void,
    ms?: number,
    ...args: any[],
): void;

We have a change in-flight to include this declaration by default. Will FLUP here once that’s released. UPDATE: these changes have rolled out widely, so if you upgrade your repository, you should now be able to use setTimeout without adding the declaration yourself or a @ts-ignore comment!

We are also looking into providing Typescript Function authors with full access to Node.js APIs as part of our roadmap this year. Stay tuned!

1 Like