nodeguy
nodeguy

Reputation: 13

NodeJS: Wait for Status Code of Post Request

Background: I have a gateway that returns the status code 200 via a post request if it is completely booted. If not it returns 500 while booting.

My idea: I have a NodeJS application which should wait until the gateway returns 200. So I created a while loop which checks the state of the gateway.

My problem: Unfortunately nothing works, the state is always true. Non of the log statements in the request will be display.

Do you have tips for me how I can fix this?

while (isGatewayUnavailable()) {
  log.info('waiting for gateway ...');
  sleep(60)
}
function isGatwayUnavailable() {
  const url = '...'
  let state = true

  request.post(url, (err, res, body) => {
    log.debug(0)
    if (err) {
      log.debug("Gateway offline");
      log.debug("err: " + err);

    }
    else if (res.statusCode === 200) {
      log.debug("Gateway online");
      state = false;
      cb(true);
    }
    else {
      log.debug("Status Code: " + res.statusCode);
    }

  });

  log.debug('return state: ' + state);

  return state;
}

Upvotes: 0

Views: 2863

Answers (1)

There is no "waiting" in JS. There's only "running code" and "running code in response to signals" (events, callbacks, promises). In this case, you want to do something based on a process that you do not control the timing of, so you can't use a synchronous function: by the time the function reaches its return keyword, you don't have any information to return yet..

So, instead of making your function return a value and having the caller wait for that value, make your code "do things once the information is in". That is, make your function either generate an event that you have a handler registered for, or pass a callback as argument so that your function can run that callback once it has the information necessary, or have it return a promise whose resolve (or reject) gets called once you have the information necessary.

1. Event-based:

const pubsub = ...;

function checkGatwayAvailability() {
  request.post(url, (err, res, body) => {
    pubsub.signal("gateway:availability", { available: ..., error: ... });    
  });
}

with caller code:

const pubsub = ...;
pubsub.register("gateway:availability", data => {...});

...

checkGatewayAvailability();

In this, the code that calls this and the code that handles the result are 100% detached from each other. Also note that pubsub isn't a real thing. Depending on your framework and APIs, there will be different ways to achieve event generation/handling, or you might even need to write your own (which really means "hit up npm and find one that is well documented and used by many folks, then use that").

2. Using a callback:

function checkGatwayAvailability(reportResult) {
  request.post(url, (err, res, body) => {
    reportResult({ available: ..., error: ... });
  });
}

with caller code:

checkGatwayAvailability( result => {
  ...
});

In this approach, the calling and handling code are coupled in the sense that your call points to the handler, even if your handler is declared somewhere completely different, like:

checkGatwayAvailability(NetworkMonitor.handleGatewayResponse);

3. Using a promise:

function checkGatwayAvailability(reportResult) {
  return new Promise((resolve, reject) => {
    request.post(url, (err, res, body) => {
      if (err) reject(err);
      resolve(...);
    });
  });
}

with caller code:

checkGatwayAvailability().then(result => {...}).catch(err => {...});

Similar to a callback, the calling and handling code are coupled, but with promises you don't "guess" at whether the resultant information is good or bad, you literally have separate code paths for the "good" cases (handled by then), and the "bad" cases (handled by catch).

3b. Using a promise through async/await syntax:

In this case, request.post does not return a Promise, your function would still need to bake its own promise, so using an async declaration doesn't make a lot of sense. We can still use the await keyword in the calling code, though:

try {
  const result = await checkGatwayAvailability();
} catch (e) {
  ...
}

but only if that caller code itself runs inside an async context.

Upvotes: 2

Related Questions