Creating a GitHub badge with Azure Functions

Recently, I spent some time with the guys from the Stryker Mutator team. First in a hackathon over a weekend back in December last year, then finalizing our work in February and launching the Mutation Score Badge. Even though I had to overcome my fear of JavaScript, I managed to find some good parts in NodeJS and combine them into a Azure Function that provides the actual mutation badge. Get the why, how and what in this post.

Why Azure Functions?

Well, simply put: because it’s cheap, easy and it supports multiple languages. Since Stryker is writting in NodeJS, I decided to challenge myself and write the function in NodeJS as well. Our setup is quite simple:

  • We use an Azure Storage Table to score all mutation scores posted from the Dashboard.
  • When someone requests a badge, the function performs a lookup in this table and presents the badge
  • We have a Function Proxy to be able to use our own domain and a friendly URL.

How we developed the function

All code was written in TypeScript and using this excellent post by Tsuyoshi Ushio, I was able to develop and debug it on my mac quite easily (well, after a crashcourse in TypeScript from Nico Jansen).

Is it really all that awesome?

No, it isn’t. We hit quite a few snags while developing but especially when deploying. As you read before, the functions are dirt-cheap on a consumption plan but this also means that they’re not ‘Always-On’. Where this doesn’t really seem to be an issue for regular C# functions, for some reason the NodeJS functions were extremely slow and on top of that, I had to use Kudu to do an npm install.

Azure and NodeJS

We soon discovered that uploading a lot of small files to Azure would take a while, and we decided we’d just want to upload the package.json and run npm install on Azure through Kudu. Notice that on this page it also says that the Node version is locked on 6.5.0. Even adjusting the WEBSITE_NODE_DEFAULT_VERSION environment variable didn’t work.

This limited us in our ability to use certain Node functionality that required version 8+ (util.promisify in particular) so we went to look for another solution. This present itself in the portal. If you look carefully at the screenshot above, you can see a variable called FUNCTIONS_EXTENSION_RUNTIME. This is set to ~1 by default, but you can simply change that to run on the ‘beta’ version. Mind you: you can only safely change this if you don’t currently have any functions deployed.

Unfortunately, it turned out that changing this to the beta doesn’t support proxies yet, so we reverted and included our own promisify.

Cold Boot

As mentioned before, we initially planned on deploying through Kudu and simply running NPM install there and we did. Thing is, the functions were really slow. I mean… REALLY slow. It took over 20 seconds to start and as it turns out, we weren’t the only ones. Our solution was to apply FuncPack and by simply running this before our publish:

npm install -g azure-functions-pack
funcpack pack ./

we were able to pack it all into one file. What it does is that it applies WebPack magic to your function (also rewriting your function.json to reference to index.js as entrypoint). Running this brought our cold boot down to acceptable levels.

What now?

Well, we’re live :) There’s still some work to do by the functions team, but with the newly announced Run-From-Zip functionality, I’m positive that it’ll run even smoother than now. On top of that, we now also know what it has cost us over the month of February: a whopping $0.33 :-) So I guess this still applies:

Or at least they make it pretty easy for Open Source projects to use their services without incurring too much of a cost penalty. I’ll follow up on this post to describe how we wrapped this all up in a neat VSTS pipeline to deploy continuously.

Share Comments