The Infrastructure Toolkit

Over the past few years - I've been lucky enough to work with some very talented people who've taught me a great deal of things about running software in Production.

One of these things was about how to build software so that it's easy to diagnose an issue when it's in Production. Essentially the Infrastructure Toolkit is an implementation of these techniques to help you build and deploy applications in a stable fashion.


Concepts

The main concept in the Infrastructure Toolkit is the Service Status Monitor. Fundamentally this is just a Boolean check for "is this thing working as intended?".

What might you want to check?

  • Can I connect to the Database?
  • Can I connect to any Dependencies?
  • How close am I to the API Rate Limit?
  • Is the percentage of Errors : Successful Status Codes within normal bounds?
  • Does the conversion rate within a given time period look ok?

Each Service Status Monitor should only be checking one thing - and get's an associated name.

Each Monitor is then available through an HTTP Endpoint - for example a monitor name of "test" would be available at /service-status/test. Once in Production - each Service Status Monitor can then be monitored via your Monitoring System - something like Sensu, Nagios or Pingdom.


Endpoints

The Infrastructure Toolkit comes with a few HTTP endpoints by default:

  • /service-status
    • This executes all of the Service Status Monitors - and returns a HTTP Status Code of 200 OK if all the monitors are successful - or a 500 Internal Server Error if one or more have failed.
    • Generally you'd want to check this at Deployment time.
  • /service-status/{monitorName}
    • This executes a single Service Status Monitor - returning an HTTP Status Code of 200 OK if it's Successful or a 500 Internal Server Error if it's not.

There's a couple of extra URLs which aren't currently part of the Swift Infrastructure Toolkit - but will be in the future. I'm noting these here as they exist in other implementations of the Toolkit in other languages. These URL's and the relevant concepts are:

  • /load-balancer
    • This returns a HTTP Status Code of 200 OK if this Instance of your application is ready for use and should be in the Load Balancer, or a 503 Service Unavailable if it's not.
  • /version
    • This returns the version number of the application.
    • Ever had someone spin up a rogue instance of your application, or an old deployment? This turns out to be really handy.

As mentioned above - over the years various people have built various implementations of the Infrastructure Toolkit for several languages, including C#, Java, Node.JS, Ruby, PHP and Go.

I've just open-sourced the Swift version of this Toolkit - both a framework-less Core and an implementation for the Vapor Web Framework. It's written in a way that it'd be pretty trivial to port this to IBM's Kitura Web Framework if you wanted too.

Adding the Toolkit to your application is really simple - there's instructions on the README file - but in-essence it's the following:

Step 1: Add the Dependency to your Swift Package Manager File

In your Package.swift add the Dependency line - like so:

import PackageDescription

let package = Package(  
    name: "SomeSwiftApi",
    dependencies: [
        .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 0, minor: 18),
        .Package(url: "https://github.com/tombuildsstuff/infrastructure-toolkit-swift-vapor.git", majorVersion: 0, minor: 1)
    ]
}

Step 2: Add one-or-more Service Status Monitors

import Foundation  
import InfrastructureToolkit

@objc
public class ExampleServiceStatusMonitor : NSObject, ServiceStatusMonitor {

    public var name : String {
        get { return "Example" }
    }

    public func checkIsHealthy() throws -> ServiceStatusResult {
        let summary = "oh hai"
        var properties = [String: String]()
        properties["foo"] = "bar"
        properties["hello"] = "there"

        let metaData = ServiceStatusResultMetaData(summary, properties)
        return ServiceStatusResult(name: self.name, successful: true, metaData: metaData)
    }

}

As shown above - optionally you can provide some metadata - for example, the last cache update time.

Step 3: Add the Routing

import HTTP  
import InfrastructureToolkitVapor  
import Vapor

let drop = Droplet(providers: [])

let monitors = [ SomeExampleMonitor() ]

drop.registerInfrastructureToolkit(monitors: monitors)

drop.get("/hello-world") {  
  (request: Request) throws -> ResponseRepresentable in
    return "Hello World"
}

let port = 5000  
drop.serve()  

Bear in mind this URL is public by default - so you either want to control access to this URL using some Middleware - or sanitise the information so that it doesn't show anything sensitive.

Step 4: Build & Run

vapor build  
vapor run  

What about Other Languages?

Fundamentally the concepts used in the Infrastructure Toolkit will work in any language.

At Ve - our primary development languages are C#, Java and PHP - so we've built internal versions of the Infrastructure Toolkit for these languages - and we're intending on open-sourcing these in the near-future. I'll be sure to update this post with links when we do.


Links & Feedback

If you're interested in using the Infrastructure Toolkit - I'd be interested to know you're thoughts. For the Swift versions - the repositories are: