Get started with decoupled modules in 4 steps

Decoupled modules help us to write clear code, focus on only one thing at a time. With EventBus library, you can get benefit of real event bus system and write decoupled modules easily.

Registering event topics

On your app init, or anytime before delivering the events we need to register our topics. For example, when we receive a payment, we will create `checkout_completed` event.

Delivering events

EventBus.EventSource module provides notify helper to deliver events without modifying your current code.

defmodule Order do

...

use EventBus.EventSource

...

event_params = %{topic: :checkout_completed, error_topic: :checkout_failed}

EventSource.notify(event_params) do

... # process the payment as usual in here and if errors then return {:error, _} tuple

end

end

end def checkout(params) doevent_params = %{topic: :checkout_completed, error_topic: :checkout_failed}... # process the payment as usual in here and if errors then return {:error, _} tupleendend

Subscribing consumers to topics

Assume that we have several operations waiting on success and failure conditions. Let’s subscribe the consumers to the event topics.

EventBus.StockUpdateService, ["^checkout_completed$", "^new_stock_arrived$", ...]})

EventBus.CargoService, ["^checkout_completed$, "^cargo_dispatched$", "^new_stock_arrived$", ...]})

EventBus.EmailService, ["^user_registered$", "^checkout_completed$", ...]})

EventBus.EventBus.Logger, [".*"]}) subscribe ({, ["^checkout_completed$", "^new_stock_arrived$", ...]}) subscribe ({, ["^checkout_completed$, "^cargo_dispatched$", "^new_stock_arrived$", ...]}) subscribe ({, ["^user_registered$", "^checkout_completed$", ...]}) subscribe ({, [".*"]})

Consuming events

EventBus consumers are just modules so they can be implemented by any kind of consumer strategy including GenStage(event_bus_postgres as sample), pooling, DynamicSupervisors, global consumers, spawn et al. So, depending on your use case, implement your consumers with the best suitable strategy. (But any kind of blocker strategies are not recommended!)

defmodule CargoService do

use GenServer

... process({topic, id}) do

GenServer.cast(__MODULE__, event_shadow)

end



def handle_cast({topic, id}, state) do

payment_data = EventBus.

# do sth with payment_data

...

# mark event as completed for this consumer

EventBus.

{:noreply, state}

end

end def) doGenServer.cast(__MODULE__, event_shadow)enddef({topic, id}, state) dopayment_data = EventBus. fetch_event_data ({topic, id})# do sth with payment_data...# mark event as completed for this consumerEventBus. mark_as_completed ({CargoService, topic, id}){:noreply, state}endend

Here is another consumer that needs all event structure and consumes with spawning: