PoolToy: A (toy) process pool manager in Elixir 1.6

Posted on July 9, 2018

 This article is part of a series on writing a process pool manager in Elixir.

This series of posts will guide you in writing an OTP application that will manage pools of processes. In particular, it will do so using features introduced in Elixir 1.6 such as the DynamicSupervisor and the Registry.

There’s quite a bit of content I wanted to cover, and I tried to present the material in a way for readers to learn (and retain!) as much as possible given the time spent. One reason for the length is that we’ll be making mistakes on our journey. Improving a skill is about learning from your mistakes, and Elixir/OTP is no different: I want you to see how/why things don’t work out sometimes, and to understand why another design is better suited. In other words, I won’t show you the “best” implementation right away, but my hope is that you’ll be better off for it: you’ll be able to think critically about your own designs and implement corrections as necessary.

Another focus is on the Observer: everybody says it’s a great tool, but beyond that you’re most often left to your own devices. We’ll periodically use the Observer as we develop PoolToy to see what’s going on in our software and to help us diagnose and fix design problems.

Without further ado, here is the contents of this series:

  1. Managing a single pool
    • Part 1.1: create a new mix project, add a worker and pool supervisor
    • Part 1.2: implement the pool manager and have our pool supervisor start it
    • Part 1.3: add the (dynamic) worker supervisor and have our pool supervisor start it ; convert our code into an OTP application
    • Part 1.4: make the worker supervisor start workers when it initializes
    • Part 1.5: implement worker checkin and checkout
    • Part 1.6: monitor client processes
    • Part 1.7: use an ETS table to track client monitors
    • Part 1.8: handle worker deaths
    • Part 1.9: make workers temporary and have the pool manager in charge of restarting them
  2. Managing multiple pools
    • Part 2.1: remove static process names, provide the worker spec dynamically
    • Part 2.2: preparing for multiple pools with the pools supervisor
    • Part 2.3: starting multiple pools, using the Registry to locate pool supervisors and stop them

Intro

This series of posts assumes that you’re familiar with Elixir syntax and basic concepts (such as GenServers and supervisors). But don’t worry: no need to be an expert, if you’ve read an introduction or two about Elixir you should be fine. If you haven’t read anything about Elixir yet, have a quick look at the excellent Getting started guide.

Processes and supervision are a core tenet of Elixir, Erlang, and the OTP ecosystem. In this series of posts, we’ll see how to create a process pool similar to Poolboy as this will give us ample opportunity to see how processes behave and how they can be handled within a supervision tree.

As a quick reminder, process pools can be used to:

  • limit concurrency (e.g. only N simultaneous connections to a DB, or M simultaneous requests to an API with rate limiting)
  • smooth occasional heavy activity bursts by queueing the excess demand
  • allocate more resources to more important parts of the system (e.g. payment processing gets a bigger pool than report creation)

Hopefully, you won’t have any trouble following along (if you struggle, please let me know!), but if you do here’s a list of alternative learning resources that might give you a different perspective and get you “unstuck”:

  • a blog post on the service/worker pattern (the code is in Erlang, but the concepts fully apply to Elixir).
  • building an OTP application from Fred Hébert’s “Learn you some Erlang”. As you can guess, it’s in Erlang and the design is a bit different (e.g. no DynamicSupervisor in Erlang, so you must use a :simple_one_for_one strategy) but even so it’s definitely worth a read to give you a better understanding about process wrangling.
  • pooly another simple process pool manager written in Elixir, but with older concepts (as it was written before they were introduced). Mainly: it uses a supervisor with a :simple_one_for_one strategy instead of a DynamicSupervisor, and doesn’t use Elixir’s registry to locate the pools.
  • the poolboy application itself (in Erlang), which is probably what you’d reach for if you need pool management in a production application

And if you’re the kind of person who prefers to just dive into the code, here it is.

Now that we’re situated, let’s get started in the next post.

 This article is part of a series on writing a process pool manager in Elixir.


Would you like to see more Elixir content like this? Sign up to my mailing list so I can gauge how much interest there is in this type of content.