What are the best strategies for handling complex task operations in Node.js Express.js?

How can I effectively manage lengthy task functions in Node.js Express.js to prevent timeout errors? Currently, my application includes a time-consuming function that does not require an immediate response but still needs to execute its tasks. How can I ensure that I receive the API response while allowing the function to run in the background?

Is there a solution to this problem? My main objective is to avoid timeout errors as the task may take a couple of minutes to complete.

What I have tried: (Using TypeScript)

import fs from 'fs'
import { v4 as uuidv4 } from 'uuid';
import { Worker } from 'node:worker_threads';

api.ts
router.post('/run-long-task', async (req, res) => {
    const taskId = uuidv4();

    const worker = new Worker(file, {
        workerData: { taskId },
        eval: true
    });

    tasksById.set(taskId, {
        status: 'running',
        started: Date.now(),
    });

    worker.on('message', async () => {
        try {
            tasksById.set(taskId, { status: 'completed' });
        } catch (error) {
            tasksById.set(taskId, { status: 'error', error: error.message });
        }
    });

    tasksById.set(taskId, {
        status: "running",
        started: Date.now(),
        worker,
    });

    worker.on("message", (status) => {
        tasksById.set(taskId, { status });
    });

    worker.on("error", (error) => {
        tasksById.set(taskId, { status: "error", error: error.message });
    });

    worker.on("exit", (code) => {
        if (code !== 0) {
            if (tasksById.get(taskId)?.status === "running") {
                tasksById.set(taskId, {
                    status: "error",
                    error: `Worker stopped with exit code ${code}`,
                });
            } else {

            }
        }
    });
    res.json({ taskId });
})

worker.ts:
import { parentPort } from "node:worker_threads";

async function performTask() {
    // Long Task Function 
 }

if (parentPort) {
    parentPort.on('message', (task) => {
        performTask()
        parentPort?.postMessage({ success: '1' });
    });
}

Answer №1

If the task is time-consuming and risks the browser timing out before completion, it's best not to run it on the main thread at all. Running it on the main thread will block subsequent calls until it's done.

Instead, consider running the task in a worker thread that operates independently of the main thread. You can establish messaging between the main thread and the worker thread for communication purposes.

If using a worker thread is not an option, handling the task becomes more complex. This may involve setting up a worker process in another location with a message queue to relay information. The intricacies of this method exceed the scope of this response.

Here is a basic example utilizing a worker thread:

// Code snippet here

This example provides a foundation that can be refined for tracking active tasks using a map structure.

Another strategy could involve initializing the worker thread at startup and instructing it through messaging to execute tasks when needed.

Answer №2

When looking at the example of T.J. Crowder, consider placing your lengthy function inside worker.ts and using parentPort.on().

index.ts:

const fs = require('fs');
var file = fs.readFileSync("./worker.ts",{ encoding: 'utf8', flag: 'r' });
const { Worker } = require('node:worker_threads');

function runService(worker) {
  return new Promise((resolve, reject) => {
    worker.on('message', resolve);
    worker.on('error', reject);
    worker.on('exit', (code) => {
      if (code !== 0)
        reject(new Error(`Worker stopped with exit code ${code}`));
    })
    worker.postMessage({toworker:"run"});
  })
}

async function run() {
  console.log(file)
  const worker = new Worker(file, {
    eval: true
  });
  const result = await runService(worker)
  console.log(result);
}

run().catch(err => console.error(err))

worker.ts:

const { parentPort } = require('node:worker_threads');
parentPort.on('message', (task) => {
  parentPort.postMessage( {success:'1'});
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What causes the low Performance score of a default NextJS Application with no content?

Just started experimenting with my initial Next.js project. Upon generating a new project using create-next-app, I decided to test its performance with the web application 'Lighthouse'. Surprisingly, although most other metrics scored above 90, ...

teasing es6 imports in unit testing

Imagine a scenario where we have a file named source.js that needs to be tested: // source.js import x from './x'; export default () => x(); The unit test code for this file is quite simple: // test.js import test from 'ava'; imp ...

Tips for showcasing varied information on Morris Chart

I am working with a Morris chart that is populated with a collection of data, each item containing 6 different data values. My goal is to switch between displaying two different sets of data. For example, I want to show the 'Target' data always ...

Rails controller did not receive the Ajax call

I have noticed that when I make an Ajax call using jQuery, the data is always transmitted (status 200), but there are times when it's not properly received by the Rails controller. The data is sent correctly, but most of the time the controller respon ...

Encountering a client component error with the app router in Next.js version 13.4.9

Encountering an error in Nextjs that persists until the 'use client' directive is removed. Warning: Rendering <Context.Consumer.Consumer> is not supported and will be removed in a future major release. Did you mean to render <Context.Con ...

Choose the Nth option in the dropdown list using programming

Currently, I have a script that dynamically populates a select box with unknown values and quantities of items. I am looking to create another script that mimics the action of selecting the Nth item in that box. Despite my research, I have been unable to ...

Ways to prevent ERR_INSUFFICIENT_RESOURCES when making AJAX requests

It's been a while since I dabbled in JavaScript, so please be patient with me. I'm currently developing an application that generates reports on student data using PHP as the backend. Periodically, we need to refresh the database used for these ...

Using Selenium and Python to scrape text from a continuously refreshing webpage after each scroll

Currently, I am utilizing Selenium/python to automatically scroll down a social media platform and extract posts. At the moment, I am gathering all the text in one go after scrolling a set number of times (see code below), but my objective is to only gathe ...

Various instances of controllers in Angular.js and JavaScript

I'm facing a challenge with a view that has two identical parts but different content. I want to find a way to use one controller and one view for both the left and right parts. Here's what I currently have in my HTML: <div class="board_bod ...

Is there a way to customize the color of the HR element in a Material-UI Select Field?

https://i.stack.imgur.com/DYeX7.png https://i.stack.imgur.com/CN0T6.png Hi there, I am currently working on a website and using a Select Field component from Material-UI. I am faced with the challenge of customizing the style to change the default light ...

The app.html for the skygear/react-chat-demo is malfunctioning

I followed the instructions provided in the Skygear manual at https://docs.skygear.io/guides/advanced/server/ The skygear-server-darwin-amd64 started successfully. Then, I attempted to run the react-chat-demo project from https://github.com/skygear-de ...

Ways to stop touch events on every element but one through JavaScript

One issue I encountered was preventing scrolling in the background while a popover is open. For desktop, it's simple with CSS: body { overflow: hidden; } The problem arose on IOS where this rule didn't work as expected and the background could ...

"Utilizing JSON parsing in Node.js and rendering the data in a Jade template

I need assistance with parsing JSON and presenting the response in a tabular format using Jade. Can you help me display the key-value pairs in two separate columns? Node.js exports.postMQinput = function(req, res) { req.assert('name', 'Q ...

retrieving a property from an ElementHandle

I'm working with Puppeteer within a Node.js module and I need to extract the text property of an HTML element selected by its XPath. Is there a more concise way to achieve this? // Retrieve the element let element = await page.$x(`xpath_expre ...

Dealing with an Incorrect Date in JavaScript

After working on a JavaScript logic to extract date and time from certain values, I realized that my approach needed some adjustments. Initially, I parsed the DateTime and converted it to a string. Then, I split the string to retrieve the date component. ...

How to best handle dispatching two async thunk actions in Redux Toolkit when using TypeScript?

A recent challenge arose when attempting to utilize two different versions of an API. The approach involved checking for a 404 error with version v2, and if found, falling back to version v1. The plan was to create separate async thunk actions for each ver ...

Obtaining the NativeElement of a component in Angular 7 Jasmine unit tests

Within the HTML of my main component, there is a my-grid component present. Main.component.html: <my-grid id="myDataGrid" [config]="gridOptions" </my-grid> In main.component.specs.ts, how can I access the NativeElement of my-grid? Cu ...

Error: Trying to call an undefined function

Having trouble with an error on this line: $("#register-form").validate. Can anyone offer assistance? Furthermore, if I write this script, how should I incorporate it into the form? Will it function without being called? <script type="text/javascript ...

Swap two frames effortlessly with just a single click!

Is there a way to effortlessly change the contents of two frames with just one click? With a single click, I'd like to modify both "framename" and "framename2" by setting their href attribute to 'qwerty' and 'qwerty2' respectively ...

Utilize jQuery and AJAX to refresh functions after each AJAX call for newly added items exclusively

I have encountered an issue with my jQuery plugins on my website. Everything functions smoothly until I load new elements via AJAX call. Re-initializing all the plugins then causes chaos because some are initialized multiple times. Is there a way to only i ...