Supervisors logic concern

Hello there,

Imagine you have many actors (which are not identified by name) behind a supervisor. If I wanted to have a facade to work with them so I can add some sort of messaging logic (i.e. round robin, hashing the sender, the message), would you add it on the supervisor or have another entity reify this behaviour and interact with them via Supervisor.wich_children? Is there even another pattern?

To put an example, lets play with coffee. Imagine I have many espresso machines in my shop and I’d like to expose this interface

Foo.order_latte(fake_bux)

Untitled%20Diagram%20(1)

Untitled%20Diagram

I’d only keep spawning and restarting logic on the Supervisor I’d love to hear what the more experienced guys has to say.

1 Like

I’d use poolboy to manage the workers. Poolboy supports FIFO and LIFO by default. I guess you could look at its implementation.
*If the pool is just workers

1 Like

There is another pattern, which is the pattern that is most commonly advised for these kinds of situations:

NomNoml diagramimage

In the diagram, a normal arrow means ‘supervises’, a dashed arrow means ‘monitors’, and a normal line means ‘calls functions of’.

So we have:

  • The EspressoMachines, just like before
  • They are supervised by a process whose only job is to restart EspressoMachines in a known state whenever they encounter a problem.
  • Next to this, we have an EspressoMachineRegistry, which is kept informed (by monitoring all of the EspressoMachines) which EspressoMachines exist. It is also the place that divides e.g. external work between them (for example, an espresso-machine that has finished making coffee will send a message here to indicate it is available for more work).
  • However, this Registry might also fail. Therefore, the registry and the EspressoMachineSupervisor are together nested within one ‘top’ supervisor, which is in charge of this whole supevision tree.
  • Outside of this, we have a module that is the external API of everything that is going on inside of here.

This is the kind of setup you’re building towards in e.g. the KV Registry (AKA the ‘Mix & OTP Guide’) on the elixir-lang homepage (specifically the 4th chapter about supervision). It also is explained in more detail in for instance ch. 9 Isolating error effects of the book Elixir in Action.

4 Likes

@Qqwy design is a very very common pattern for the problem OP mentioned.

However @Charlyzzz I would question if you actually need some sort of messaging logic. Just let the Supervisor add as many children as it needs and not constrain it. By default the current BEAM can handle over 260k processes. Constraining in any way complicates the architecture and BEAM’s fail-safe mind-set.

2 Likes

I’d use poolboy to manage the workers […]

This was the second thing that came to my mind.

Thanks for your answer. I’ll try to dig more into it and make an example. I had in my mind that KV.Bucket example, but couldn’t remember where it was.

What puzzled me was that in Akka this concept is reified as Routers and here it’s not provided out of the box. Maybe it’s an opportunity for a new library? :stuck_out_tongue:

Thanks guys, I’m heading back for some experimenting.

I think you are mentioning the example mentioned in the official elixir guide.

https://elixir-lang.org/getting-started/mix-otp/dynamic-supervisor.html