Home > Software design >  asynch await ping() function setInterval(). How to make it smart?
asynch await ping() function setInterval(). How to make it smart?

Time:12-23

The following code pings an NGINX location block on my NGINX server to give you a health check status.

const ping = async () => {
  const url = `http://10.10.1.100/status`;
  const postData = {
    method: 'POST', // *GET, POST, PATCH, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    headers: {
      'Content-Type': 'text/plain; charset=ASCII'
    },
    body: 'PING'
  }
    try {
      let factor = 1;
      let timeout = 3000; // ms
      let start = (new Date()).getTime();
      const request = await fetch(url, postData);
      let delta = new Date().getTime() - start;
      delta *= (factor || 1);
      if(delta > timeout) throw new Error(`PONG > ${timeout}ms. Server down?`);
      if(!request.ok) throw new Error(`${request.status} ${request.statusText}`);
      const response = await request.text();
      if(!response) throw new Error(`${response}`);
      document.getElementById('serverPongSpeed').innerText = `${delta.toFixed(0)}ms`;
      // Do Something...
      console.log(`%c${delta.toFixed(0)}ms ${response}`, "color: #c6ff00"); // Lime A400
    } catch (error) {
        console.log(error);
    }
}

The NGINX location block:

location = /status {
  access_log off;
  default_type text/plain;
  add_header "Access-Control-Allow-Methods" "POST";
  add_header "Content-Type" "text/plain";
  return 200 "PONG";
}

Right now I run it like this:

setInterval(ping, 3000); // Every 3 seconds

The problem is, during testing, when I turn off NGINX to see what happens the PING doesn't break. It just keeps sending POST requests.

Maybe it's an error I am not catching? Or maybe there is no error because the fetch has a greater timeout? Maybe setting a fetch timeout at 3 seconds would fire something for me to catch..

CodePudding user response:

Below is a revised, complete example of the desired working solution.

The javascript asynch await ping function:

  1. Ping function set to POST a request to NGINX /status location block.
  2. Ping function set to timeout at 300ms to indicate possible server down.
  3. Ping function set to indicate increased network latency using preset thresholds.
  4. Ping function set to catch network level error and any other unknown error.
  5. Ping function returns output to Console.

...

// Settings
const settings = {
  pingInterval: 1000, // ms
  latency: {
    factor: 1.0, // Adjust latency to a percentage of its total
    high: 99, // ms
    moderate: 66, // ms
    low: 33, // ms
  },
  timeout: 300, // ms
  consoleLogLimit: 10,
  consoleLogCount: 0,
};

const ping = async() => {

  const url = `http://10.10.1.100/status`;

  const postData = {
    method: 'POST', // *GET, POST, PATCH, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    headers: {
      'Content-Type': 'text/plain; charset=ASCII'
    },
    body: 'PING'
  }

  try {

    let startWatch = (new Date()).getTime();

    const request = await fetch(url, postData);

    let stopWatch = (new Date().getTime() - startWatch) * (settings.latency.factor || 1);

    if (!request.ok) throw new Error(`${request.status} ${request.statusText}`);

    const response = await request.text();

    if (!response) throw new Error(`${response}`);

    if (stopWatch >= settings.timeout) {
      throw new Error(`PONG > ${settings.timeout}ms. Server down?`, "color: #d500f9"); // purple A400
    } else if (stopWatch >= settings.latency.high) {
      console.log(`%c${response}: ${stopWatch}ms High Latency`, "color: #ff1744"); // red A400
    } else if (stopWatch >= settings.latency.moderate) {
      console.log(`%c${response}: ${stopWatch}ms Moderate Latency`, "color: #ffc400"); // amber A400
    } else if (stopWatch <= settings.latency.low) {
      console.log(`%c${response}: ${stopWatch}ms Low Latency`, "color: #00e676"); // green A400
    }

  } catch (error) {

    // Catch network level error
    if (error instanceof TypeError && error.message == 'NetworkError when attempting to fetch resource.') {
      console.log(`%cPING: ${settings.timeout}ms timeout. Server down?`, "color: #651fff"); // purple A400
    } else {
      // Catch any other error
      console.log(error);
    }

  } finally {

    settings.consoleLogCount  ;

    // Prevents browser from getting sluggish   
    if (settings.consoleLogCount > settings.consoleLogLimit) {
      // Reset limit
      settings.consoleLogCount = 0;
      // Clear console
      console.clear();
    }

  }

}

setInterval(ping, settings.pingInterval);

...

The NGINX server /status location block:

  1. End point set to accept POST only requests on /location end point.
  2. End point access log set to disabled because we don't really need to log this.
  3. End point set to respond with content type set to text/plain.
  4. End point set to accept POST requests from any origin.
  5. End point set to return a Content-Type of text/plain with a text "PONG" response on success.

...

location = /status {

  access_log off;

  default_type text/plain;

  limit_except POST {

    deny all;

  }

  add_header Access-Control-Allow-Origin "*" always;
  add_header Access-Control-Allow-Methods "POST, OPTIONS" always;
  add_header Content-Type "text/plain" always;

  return 200 "PONG";

}

CodePudding user response:

you can use ClearInterval() method like this:

  var interval = setInterval(ping, 3000);
  if(timeoutCounter > 3)
      clearInterval(interval)

you need some more code to count the time outs/ errors. something like circuit breaker pattern

  • Related