Get your bash scripts to sleep (halt execution) on Shippable and Travis

As I write this, it’s been about 36 hours without sleep for me — enough to relate to the importance of sleeping. However, this discussion is around getting a bash script or JavaScript on NodeJS to sleep for a specific duration.

#!/usr/bin/env bash

echo "Feeling drowsy...";
sleep 10;
echo "Woof! Back up after 10 seconds!";

The sleep command in unix allows one to pause execution of a script for a specified duration. It is a very handy tool in times where a script needs to wait for some other asynchronous work to complete. (Kindergarten talks for many!)

What’s the fuss?

In my case, I was working on creating a script that starts a SailsJS server and runs sanity test on the server’s API using Newman. The server had to be started as a daemon so that we could start the server and then execute the command to run the tests. pm2 or foreverjs are good tools to daemonise NodeJS servers.

#!/usr/bin/env bash

echo "Starting server...";
pm2 start app.js;

echo "Running tests...";
newman -x -y 10 -c test/sanity.json.postman_collection;

echo "Stopping server...";
pm2 stop app.js;

The above script might seem to appear just fine, but in reality, no tests get executed. Simple reason — SailsJS servers often take a good 10 seconds to execute all initialisation scripts and be operational. pm2 triggers the server start and immediately goes to execute Newman tests and within that time the server is not yet ready to accept API requests.

The prognosis

Get the script to sleep for a few seconds before executing Newman tests. We already know how to do that. 🙂

Sadly, this is not the simple solution that would truly fix the problem. Culprit being quite a few:

  • If your bash scripts has SLEEP command in them, it would not work in a number of Continuous Integration services such as Shippable, Travis-CI, etc. All of these services have some other way to pause execution using configuration options — but that is not a viable option if you intend to have a common script for both local and CI testing. (Good practice.)

  • It does not work on Windows® Command Prompt (what does?)

The solution

In place of the sleep command, we could write a line of JavaScript code that runs an infinite loop until a specified time is reached. We could use the -e parameter of node to pass a line of script to be executed. Neat! (Is it?)

<

pre class=”lang:sh decode:true ” >node -e “n=Date.now;s=n();while(n()-s<5000);”; # 5 seconds delay

or

node -e "setTimeout(null,5000)"; # 5 seconds delay

I decided to make things neater by publishing this as a module called sleep-ms, which would provide a CLI command to do the same thing as above. Since I was already running the script on systems having Node, adding an additional global module was not a tough job.

npm install sleep-ms -g;

With this, the above code changes and becomes interoperable between local and restricted systems.

#!/usr/bin/env bash

echo "Starting server...";
pm2 start app.js;

echo "Waiting 5 seconds to complete server boot...";
sleepms 5000;

echo "Running tests...";
newman -x -y 10 -c test/sanity.json.postman_collection;

echo "Stopping server...";
pm2 stop app.js;

Leave a Reply