AdamInTheOculus
AdamInTheOculus

Reputation: 370

How can I receive real-time updates from a long asynchronous process?

I'm writing a small, internal web application that reads in form data and creates an excel file which then gets emailed to the user.

However, I'm struggling to understand how I can implement real-time updates for the user as the process is being completed. Sometimes the process takes 10 seconds, and sometimes the process takes 5 minutes.

Currently the user waits until the process is complete before they see any results - They do not see any updates as the process is being completed. The front-end waits for a 201 response from the server before displaying the report information and the user is "blocked" until the RC is complete.

I'm having difficulty understanding how I can asynchronously start the Report Creation (RC) process and at the same time allow the user to navigate to other pages of the site. or see updates happening in the background. I should clarify here that the some of the steps in the RC process use Promises.

I'd like to poll the server every second to get an update on the report being generated.

Here's some simple code to clarify my understanding:

Endpoints

// CREATE REPORT
router.route('/report')
  .post(function(req, res, next) {

    // Generate unique ID to keep track of report later on.
    const uid = generateRandomID();

    // Start report process ... this should keep executing even after a response (201) is returned.
    CustomReportLibrary.createNewReport(req.formData, uid);

    // Respond with a successful creation.
    res.status(201);
  }
}

// GET REPORT
router.route('/report/:id')
.get(function(req, res, next){

  // Get our report from ID.
  let report = CustomReportLibrary.getReport(req.params.id);

  // Respond with report data
  if(report) { res.status(200).json(report); }
  else { res.status(404); }
}

CustomReportLibrary

// Initialize array to hold reports
let _dataStorage = []; 

function createNewReport(data, id) {

  // Create an object to store our report information
  let reportObject = {
    id: id,
    status: 'Report has started the process',
    data: data  
  }

  // Add new report to global array.
  _dataStorage.push(reportObject);

  // ... continue with report generation. Assume this takes 5 minutes.
  // ...
  // ... update _dataStorage[length-1].status after each step
  // ...
  // ... finish generation.
}

function getReport(id) {
  // Iterate through array until report with matching ID is found.
  // Return report if match is found.
  // Return null if no match is found.
}

From my understanding, CustomerReportLibrary.createNewReport() will execute in the background even after a 201 response is returned. In the front-end, I'd make an AJAX call to /report/:id on an interval basis to get updates on my report. Is this the right way to do this? Is there a better way to do this?

Upvotes: 1

Views: 178

Answers (1)

rkm
rkm

Reputation: 3151

I think you are on the right way. HTTP 202 (The request has been accepted for processing, but the processing has not been completed) is a proper way to handle your case.

It can be done like this:

  1. client sends POST /reports, server starts creating new report and returns:

    202 Accepted
    Location: http://api.domain.com/reports/1
    
  2. client issues GET /reports/1 to get status of the report

All the above flow is async, so users are not blocked.

Upvotes: 1

Related Questions