Remember what it was like building web apps before modern web frameworks? It was a lot of work! The structure and conventions that web frameworks gave us brought on a new level of rapid development, best practices, and collective understanding of the problem domain. Frameworks lowered the barrier to entry in building web sites and web applications.
Many web developers, including myself, then started to look at more complex problems that involved more than just rendering web pages. What became interesting was building web applications or web services that actually did something -- not just provide a fancy interface to a database.
One of the first of these I remember building was the original version of Mailhooks. It was a web app that would also accept incoming email (be an SMTP server), parse the email, then post it via HTTP to a URL. This is what forced me to learn Twisted and async evented programming some four or five years before all this Node.js hype.
More recently (though still some time ago) I built Localtunnel, which almost doesn't qualify as a web app. It's a service that will expose a locally running web server to the rest of the Internet from a single command. The server was a combination of an HTTP reverse proxy, a registeration web API, a tunneling service, and some glue.
These days I work at Twilio, which to most people is a just web API, but it's backed by a fairly complex service-oriented architecture full of databases, queues, gateways, processors, and all kinds of specialized services. And then there's the infrastructure to make all that stuff work!
Except for a minor subset of Mailhooks and the actual API and website of Twilio, none of these examples would benefit from a web framework. The rest are these server daemons, not necessarily web servers, but IO-bound long-running background processes. They may provide multiple servers on different ports, and very often include some persistent client connection to another server. Or maybe they collect data and serve nothing; storing, transforming, or passing the data along somewhere else. Perhaps it's a TCP proxy with some special routing logic.
These "services" don't have the equivalent of a web framework. Every time you write one, it's like you're starting over. Unless you borrow code from the last one you wrote. But when the majority of your system is made up of these non-web services, it starts to feel silly that you have web frameworks but not service frameworks.
This is what Ginkgo is: a framework and toolkit for building services.
Ginkgo evolved out of a slow realization of what a service is and how to best build large service applications. The key insight is something that is potentially not specific to Ginkgo, in the same way MVC is not specific to any web framework. I call it the service model.
Consider Twilio, for example. In very general terms, Twilio is a service. People use it as a way to make, receive, and control telephone calls and text messages programmatically. It can be broken down into several sub-services: Voice, SMS, and Client. Client is how we give developers an actual media pipe into Twilio.
[image: twilio -> voice, sms, client]
Each of these product sub-services is then made up of a number of sub-services. In this case, the sub-services for Voice, SMS, and Client are the different daemons that interact to power that product. One of these is a daemon called Matrix that handles signalling and messaging. It turns out, this daemon has a number of sub-components or sub-services. And some of them even have further sub-services.
[image: twilio -> client -> matrix -> jetmesh -> client, server]
What we end up having is this component hierarchy, where each component is a service -- something that continuously runs for some purpose. There's a name for what this hierarchy represents: service composition. It turns out in practice, to a better or worse degree, large systems providing a service get broken into smaller systems, which are broken into smaller systems, etc, etc. Every service is composed of smaller, simpler services.
The service model just formalizes this idea and strives for "services all the way down." Each service is just a special object acting as a module that nests into these hierarchies and knows how to start, stop, and reload.
This little bit of structure and convention turns out to go a long way. Ginkgo's implementation then includes some support around this convention. For example, there is a runner that can be used to actually start and daemonize a service (and all its children) without writing an entry-point script. There's also a service manager utility for easily stopping, restarting, and reloading a running service. Then there's a configuration system that lets services define their own settings, but then let you configure the entire service hierarchy in one place. Configuration is integrated with reloading, so you get runtime configuration reloading for free.
Now, if you wanted to run part of your service hierarchy in a seprate process, you can just point the runner at that sub-service, maybe on a completely different host. For now, how your services communicate across processes is up to you, but that's exactly the type of problem a Ginkgo "standard library" should be solving in the near future.
Concurrency is an important part of building these services, so maybe it's odd it hasn't been brought up yet. The service model is actually quite orthogonal to most concurrency models. As an example, Ginkgo was originally created for gevent using greenlets (green threads), which could easily be replaced by actual threads. But this service model idea was heavily influenced by the Twisted Application Framework, and Twisted is more traditional single-threaded callback-oriented concurrency. So it really doesn't matter what concurrency model you're using to use the service model.
That said, Ginkgo was originally designed for gevent and greenlets. So in Ginkgo, any greenlet should belong to a service. Services are containers for greenlets. This helps make services more self-contained and helps you manage your greenlets. When you stop a service, it will kill any running greenlets for you.
Given this useful bit of structure, Ginkgo builds on it with convenience mechanisms. For example, service objects have their own spawn() and spawn_later() methods that will automatically put the greenlet in the service's greenlet pool. Since most of the time the function target for spawning a service greenlet are defined in the service, there's also an @autospawn decorator for service methods that will automatically wrap them in the service's spawn() metohd when called.
Lastly, while gevent is great, there are still times when you need threads. Or sometimes even multiprocessing. It turns out, the API for dealing with these different "async" processing mechanisms is pretty much the same. So Ginkgo intends to abstract these mechanisms, giving each service implementation a common way to deal with concurrency using a different "AsyncManager". Some services may use greenlets, some may use threads, some may use subprocesses, but they'll all be managed by a service using the same interface.
To sum up: Ginkgo is a lightweight service framework and toolkit. It's based on the service model, which is just the idea of creating hierarchies of services. Services are just objects representing a component of a "long-running" system, that may contain other services, and that know how to start, stop, and reload. They also have their own configuration, manage concurrency primitives, and can be run and managed by the Ginkgo runner.
It's the first general "service framework" I've seen. Though a lot of credit goes to Twisted's application framework, which does a lot of the same things and was a big influence on Ginkgo. However, Ginkgo's model is general enough you could implement it in any language. This would introduce the advantage of a common conceptual framework for implementing services across languages.
Ginkgo was developed as an open source project while working at Twilio. Once adopted internally it created an explosion of new services, so not only is it being used in production, it has proven to provide the benefits of a framework while remaining very, very simple.
Now build lots of services!