4

A part of a system I am currently reviewing, consists of a master node which calls several slave nodes using REST APIs.

The slave nodes are scattered throughout the world on different servers, and the master can run the job on the servers up-to every minute. The result of the API call will not take longer than about 50 seconds. Both the master and the slave are based on node.js, with the slaves using Express framework.

For reference, here is a simplified diagram: master communicating with three slaves using REST

Once the master node makes requests to all slave nodes, it waits for all requests to either complete (or timeout), and processes the resulting data.

According to this StackOverflow post, it is not okay for a web application to wait several minutes before returning a response. What about in a case where the job takes less than a minute, but still more than a few seconds, is it appropriate to use a blocking REST call in this way? Considering that this is a non-public API, the fact that a slave failure/unavailability is still considered useful data for the master node as well as the fact that the master cannot proceed without data from all slaves.

  • Does Master sends the upstream requests sequentally? Does it has to process the responses in specific order? – Laiv Mar 14 at 16:26
  • @Laiv it calls the events asynchronously at the same time, the order doesn't matter at all. – J. Pinkman Mar 18 at 23:42
8

The key insight here is to treat job activations as resources that have a significant lifetime.

In a similar situation, I have implemented job creation using a POST method that returns a "202 Accepted" response with the location of the newly created job.

The client can then poll the status of this job until it is finished.

To avoid unreasonably frequent polling or unnecessary delays, I'm using a HTTP Prefer header with a wait attribute for the polling requests, which works reasonably well. I can't judge whether I'm fully within the usage patterns as intended by the RFC authors, but as this is an internal application with client and server coded by me, this doesn't really matter.

0

According to this StackOverflow post, it is not okay for a web application to wait several minutes before returning a response

I would dare to say that it's not convenient for the major part of the web developments out there. The problem is not at keeping connections alive, it's rather locking resources on the server-side. Creating, executing and holding thread executions is costly, mainly in terms of memory. The thing is that, if we don't release resources as soon as possible, the capacity of the server for allocating more threads decrease, an so does its throughput.

Fortunately, that should not be a problem for you since NodeJS is mono-thread and it doesn't lock resources and remain idle until it gets responses back from the remote servers. At least it won't do it by default. However, if you force it to wait for responses, you will turn a non-blocking performant IO into a non-so-performant and blocking one, what would defeat the purpose of NodeJs in the first place.

it calls the events asynchronously at the same time, the order doesn't matter at all

Then wait for the responses asynchronously too. This situation seems suitable (IMO) for an enterprise integration design pattern based on messages. Briefly summarised, it could be something similar to :

  • The master starts a new transaction and identify it with a correlation identifier or Transaction ID.
  • The master sends a message to each slave involved in the transaction. The message includes the transaction ID, the instructions and the endpoint to report to.
  • The slave do the job and send the report (result) back to the master by request to the endpoint informed

For example:

{   
    "headers":{ 
      "Transaction-ID":"xxxx", 
      "Transaction-URI":"proto://host:port/endpoint/transaction/xxxx"
      "Created":"yyyy-MM-ddTHH:mm:ssZ" 
    }, 
    "body":{ ... }     
}

the fact that a slave failure/unavailability is still considered useful data for the master node as well as the fact that the master cannot proceed without data from all slaves.

Here we have two options. On one side we can make the master don't care about how long takes for all the slaves to respond. On the other hand, provide the transaction with a timeout. -The result of the API call will not take longer than about 50-. Looks like we already know the duration of the timeout. After that time, the master marks the transaction as finished/unfinished and it no longer updates the state whether the slaves do respond or not.

If we make the endpoint idempotent, slaves shall not care whether they are on time or not, they will just send an "update" to the indicated endpoint.

Altogether, the whole process is very fire-and-forget, and this is ((naively oversimplified) what NodeJS is all about.

Considering that this is a non-public API

It doesn't matter.

Finally, the master can proceed as @Hans-MartinMosner suggests. It can respond with Http Status 202 Created to the clients, alongside with an estimation (in seconds) for the client to wait before proceed with the next call to fetch the transaction state.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.