Node.js vs Bash

On April 1st the Raspberry PI foundation published a blog post The little computer that could where they described in detail how Raspberry PI Model 3s were now serving all the traffic for the site.

The challenge

There were an unspecified number of PIs each hidden behind a load-balancer.

The first person to tweet all the hex identifiers to Mythic Beasts wins absolutely nothing other than the respect of the Raspberry Pi community.

Each web request would give away a clue to its hex identifier through an additional property in the HTTP header when fetched (X-Served-By).

With the challenge set in place, I opened a text editor (Atom) and started typing in some code in Node.js.

var request = require('request')
var async = require('async')

Without realising I'd decided to solve the problem with the programming language I was currently using on a daily basis.

Node.js solution #1

I posted this solution into the comments along with the results.. They were:

Raspberry Pi a
Raspberry Pi e
Raspberry Pi 6
Raspberry Pi 12
Raspberry Pi 1a
Raspberry Pi 2
Raspberry Pi 16
Raspberry Pi 1e

Pros:

  • async.while() gives a clean way to solve the problem of running asynchronous loops.
  • node.js is highly portable running on Windows, Linux 64-bit, ARM v6 and v7 with many binaries available
  • Uses only one process/thread
  • Easy to extend for timing or additional logic

Cons:

  • Async is hard to understand, especially without having been exposed to it
  • Callbacks are kind of verbose too
  • Runs to infinity.. Control+C when satisfied.

Do you use Docker? You can run the example through the two scripts build_docker.sh and run_docker.sh held in the Github repo. Just remember to hit Control + C!

Bash solution #1

Then someone posted this, followed up by a comment saying it was 'way nicer' than the node code.

for i in {1..100} ; do HEAD -E https://www.raspberrypi.org/ ; done | grep X-Served-By | sort | uniq

Pros:

  • I have to admit that this code is really concise
  • Bash is trendy at the moment with Bash on Windows coming soon
  • Human-readable pipes like sort and uniq

Cons:

  • Lack of portability
  • Does not run on a Raspberry PI.. well only if you run Raspbian. HEAD is a command available in a Perl package that needs to be fetched separately
  • Doesn't work on vanilla Mac OS
  • Doesn't work on vanilla Windows
  • Creates 100 processes!!
  • Still leaves in the text "X-Served-By

Bash solution #2

I had a Mac to hand so I wondered if I could convert the code to run through curl easily.

HEAD became curl and portable to Git for Windows and Mac OS.

curl -s -I https://www.raspberrypi.org/

I then used the cut command to select all the text to the right of the : symbol. The separator is defined with -d":" and -f 2 means (field) 2.

for i in {1..100} ; do curl -s -I https://www.raspberrypi.org/ ; done | grep X-Served-By | cut -dā€:ā€ -f 2 | sort | uniq

Pros

  • Gives the correct formatted text
  • Is true to the original solution
  • Much more portable, Raspbian although a wonderful thing is not the only OS being used by developers.

Cons

  • Still runs with 100 processes

What would you do?

Can you suggest a way of doing this in pure bash without creating so many processes? How about in your favourite programming language?

Head over to Github and fork the code now. I'll merge in PRs adding your solution to the public repository.

Important update: You may find that running the code results in two VMs being returned instead of the full set. I've also included a fake endpoint in the Github repo. You can test against this without going to the public Internet.

You will find a tiny Node.js web-server in the fakeendpoint folder - it will run on port 3000 - i.e. http://localhost:3000/ in a web browser.

$ cd fakeendpoint/
$ node app.js 
Listening on port 3000

Alex Ellis

Read more posts by this author.

Subscribe to Alex Ellis' Blog

Subscribe to keep in touch. By providing your email, you agree to receive marketing emails from OpenFaaS Ltd

or subscribe via RSS with your favourite RSS reader

Learn Go with my new eBook

eBook cover

"Everyday Go" is the fast way to learn tools, techniques and patterns from real tools used in production based upon my experience of building and running OpenFaaS at scale.

Buy a copy on Gumroad