Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

am-kantox/siblings

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Siblings    Kantox ❤ OSS  Test  Dialyzer

The partitioned dynamic supervision of FSM-backed workers.

Usage

Siblings is a library to painlessly manage many uniform processes, all having the lifecycle and the FSM behind.

Consider the service, that polls the market rates from several different sources, allowing semi-automated trading based on predefined conditions. For each bid, the process is to be spawn, polling the external resources. Once the bid condition is met, the bid gets traded.

With Siblings, one should implement c:Siblings.Worker.perform/3 callback, doing actual work and returning either :ok if no action should be taken, or {:transition, event, payload} to initiate the FSM transition. When the FSM get exhausted (reaches its end state,) both the performing process and the FSM itself do shut down.

FSM instances leverage Finitomata library, which should be used alone if no recurrent perform should be accomplished or if the instances are not uniform.

Typical code for the Siblings.Worker implementation would be as follows:

defmodule MyApp.Worker do
  @fsm """
  born --> |reject| rejected
  born --> |bid| traded
  """

  use Finitomata, @fsm

  def on_transition(:born, :reject, _nil, payload) do
    perform_rejection(payload)
    {:ok, :rejected, payload}
  end

  def on_transition(:born, :bid, _nil, payload) do
    perform_bidding(payload)
    {:ok, :traded, payload}
  end

  @behaviour Siblings.Worker

  @impl Siblings.Worker
  def perform(state, id, payload)

  def perform(:born, id, payload) do
    cond do
      time_to_bid?() -> {:transition, :bid, nil}
      stale?() -> {:transition, :reject, nil}
      true -> :noop
    end
  end

  def perform(:rejected, id, _payload) do
    Logger.info("The bid #{id} was rejected")
    {:transition, :__end__, nil}
  end

  def perform(:traded, id, _payload) do
    Logger.info("The bid #{id} was traded")
    {:transition, :__end__, nil}
  end
end

Now it can be used as shown below:

{:ok, pid} = Siblings.start_link()
Siblings.start_child(MyApp.Worker, "Bid1", %{}, interval: 1_000)
Siblings.start_child(MyApp.Worker, "Bid2", %{}, interval: 1_000)
...

The above would spawn two processes, checking the conditions once per a second (interval,) and manipulating the underlying FSM to walk through the bids’ lifecycles.

Worker’s interval might be reset with GenServer.cast(pid, {:reset, interval}) and the message might be casted to it with GenServer.call(pid, {:message, message}). For the latter to work, the optional callback on_call/2 must be implemented.

Sidenote: Normally, Siblings supervisor would be put into the supervision tree of the target application.

Installation

def deps do
  [
    {:siblings, "~> 0.1"}
  ]
end

Changelog

  • 0.11.3 — OTP26 ready
  • 0.11.2 — [FIX] wrong specs for start_link/1 and child_spec/1
  • 0.11.1 — upgraded to Finitomata (v0.11.0)
  • 0.11.0 — throttler → generic + on perform
  • 0.10.3 — accept {(any() -> :ok), timeout} as die_with_children, write-only InternalState
  • 0.10.2 — accept (any() -> :ok) as die_with_children option as a callback
  • 0.10.0die_with_children: boolean() option
  • 0.8.2 — updated with last finitomata compiler
  • 0.7.0Siblings.state/{0,1,2,3} + update to Finitoma 0.7
  • 0.5.1 — allow {:reschedule, non_neg_integer()} return from perform/3
  • 0.5.0 — use FSM for the Sibling.Lookup
  • 0.4.3 — accept hibernate?: boolean parameter in call to Siblings.start_child/4 to hibernate children
  • 0.4.2 — accept workers: in call to Siblings.child_spec/1 to statically initialize Siblings
  • 0.4.1 — [BUG] many named Siblings instances
  • 0.4.0Siblings.{multi_call/2, multi_transition/3}
  • 0.3.3Siblings.{state/1, payload/2}
  • 0.3.2Siblings.{call/3, reset/3, transition/4}
  • 0.3.1 — retrieve childrens as both map and list
  • 0.3.0GenServer.cast(pid, {:reset, interval}) and GenServer.call(pid, {:message, message})
  • 0.2.0 — Fast Worker lookup
  • 0.1.0 — Initial MVP

About

The partitioned dynamic supervision of FSM-backed workers

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages