In some of my projects I have been using the Play framework, and so I was looking how to smoothly introduce
autobreaker in those projects. Play uses Guice as its default dependency injection framework. With the help of custom annotations, I’ve created a Guice extension to wrap objects with
autobreaker. The result allows you to do the following:
To make it clear, the concrete implementation of
MyServiceImplementation, will be
autobreaker-enabled™ once injected in another class.
In order to accomplish this, I’m using Guice’s service provider interface (SPI). Guice does allows methods to be intercepted through AOP. Implementations of
MethodInterceptors can be defined, and are executed whenever a matching method is invoked. According to the documentation
Since interceptors may be applied to many methods and will receive many calls, their implementation should be efficient and unintrusive.
Unfortunately, I wasn’t interested on individual methods, but whole objects, where each would have some shared logic. In this case, a common circuit breaker for the full instance. Besides that,
autobreaker is a generic framework already using Proxy, and I didn’t want to reinvent the library in order to make it work with Guice.
Therefore, I decided to provide conveniences to transform modules on demand. Given an existing module, the helper code can iterate over the existing bindings and transform them case necessary. If the binding is not annotated, it simply adds it to the resulting module. Otherwise, we replace it with another binding that uses a provider. The provider, in turn, receives the injector, so it can get the originally binded instance, and return it wrapped on
autobreaker. In a high level, the code looks like the following:
The full implementation can be found on GitHub, and works with linked key bindings and concrete instances. Furthermore, I’ve created an extension to allow wrapping bindings more easily. The result is the code introduced on the beginning of the post.
Nonetheless, if one doesn’t want to use
AutoBreakerModule, the helpers can be used directly by doing this:
- Circuit Breakers and retries in Scala with autobreaker
- Services Version Lock with Docker and Jenkins
- O(1) LFU Cache in Scala
- Efficient Timer using a Circular Buffer
- Problems with Branches per Environment
- Trunk Based Development with Multiple Services
- Type Equality Checking at Compile Time in Scala
- Erlang, Elixir and a simple Supervisor
- RFID, Dryers, and IoT
- Boilerplate-free Typed Settings generation with Scala Macros