MIT licensed by Roman Gonzalez
Maintained by [email protected]

Capataz

Our greatest glory is not in never failing, but in rising every time we fail.– Confucius

Table Of Contents

Raison d’être

As time progresses, I’ve come to love developing concurrent applications in Haskell, its API (STM, MVars, etc.) and light threading RTS bring a lot to the table. There is another technology that is more famous than Haskell in regards to concurrency, and that is Erlang, more specifically its OTP library.

If you wonder why that is, you may need to look into the OTP library design, actors systems (in general) provide an architecture that enables applications to be tolerant to failure through the enforcement of communication via message passing and by making use of a critical infrastructure piece called a Supervisor.

After trying to replicate Erlang’s behavior on Haskell applications by using the distributed-process library (a clone of OTP), and after implementing several (disposable) iterations of actor systems in Haskell, I’ve settled with just this library, one that provides a simple Supervisor API.

This library is intended to be a drop-in replacement to forkIO invocations throughout your codebase, the difference being, you’ll need to do a bit more of setup specifying supervision rules, and also pass along a reference of a supervisor for every thread you fork.

Why not distributed-process?

distributed-process is an impressive library, and brings many great utilities if you need to develop applications that need to be distributed and reliable. However, it is a heavyweight solution that will enforce serious changes to your application. This library is intended to provide the reliability benefits of distributed-process, without the constraints imposed by the distributed part.

Why not a complete actor system?

Actor systems are very pervasive, they impose specific design constraints on your application which can be rather expensive. This library attempts to bring some of the reliability benefits of actor systems without the “change all your application to work with actors” part of the equation.

That said, this library can serve as a basis for a more prominent library that provides an opinionated Inter-Process communication scheme. If you happen to attempt at doing exactly that, please let me know, I would love to learn about such initiatives.

Why not async?

async is a fabulous library that allows Applicative composition of small asynchronous sub-routines into bigger ones and link errors between them. Given this, async fits the bill perfectly for small operations that happen concurrently, not necessarily for long living threads that need to be restarted. This library attempts not to replace async’s forte, but rather provides other benefits not found in async, like automatically restarting threads with a given recipe under error situations.

Documentation

Documentation can be found here

Installation

Hackage Stackage LTS Stackage Nightly

Make sure you include the following entry on your cabal file’s dependecies section.

library:
  build-depends: capataz

Or on your package.yaml

dependencies:
- capataz

Development

Build Status Github Hackage Dependencies

Follow the developer guidelines

In future releases

  • Replace Protolude in favor of RIO
  • Documentation of performance analysis
  • Documentation improvements
  • capataz-dashboard package that provides web-ui with Supervisor statistics
  • Ensure unit tests always finish on all concurrent scenarios (dejafu experiment)

Changes

Change log

capataz uses Semantic Versioning. The change log is available on GitHub.

v0.1.0.1

  • Bump bounds of async dependency

v0.1.0.0 Who supervises the supervisor?

BREAKING CHANGES

  • Introduction of the Process type which is composed of both Supervisor and Worker types
  • Replace defWorkerSpec in favor of workerSpec and workerSpecWithDefaults to build static workers
  • Replace of defWorkerOptions in favor of buildWorkerOptions and buildWorkerOptionsWithDefaults to build dynamic workers
  • Replace terminateWorker in favor of terminateProcess
  • Add supervisorSpec, supervisorSpecWithDefaults to build static supervision trees
  • Add forkSupervisor, buildSupervisorOptions and buildSupervisorOptionsWithDefaults to build dynamic supervision trees
  • Replace usage of default records semantics in favor of Lenses
  • Add joinCapatazThread to avoid providing direct access to async of root supervision tree
  • Add getSupervisorProcessId to access the ProcessId of a given Supervisor record (for dynamic termination)
  • Add getSupervisorAsync to access the Async () record of a supervisor process thread
  • Add getCapatazTeardown to access the Teardown record of the capataz system
  • Move CapatazEvent records to new module Control.Concurrent.Capataz.Event to avoid requiring DuplicateRecordFields extension on API users
  • Remove WorkerAction alias as it is used for library development documentation
  • Add capataz-repo-watcher example to showcase static supervision trees
  • Update capataz-simple-example unix-process example
  • forkCapataz signature now requires name for root supervisor

v0.0.0.2

  • Bump bounds of tasty dependency

v0.0.0.1

  • Bump bounds of tasty dependency
  • Bump bounds of tasty-hunit dependency

v0.0.0.0

  • First release of capataz
  • Support for supervising simple worker IO () sub-routines