chemist

chemist

CQRS/ES commanded questions

Hi, I am working with the commanded library and will love to hear some of your views.

  1. What is the difference between a saga and a process manager? Because I sense the process manager in commanded should be named a saga as it does route messages across multiple discrete contexts/aggregates.

  2. How should I write compensating actions using commanded proc mgr?

For example, let’s say I create a wallet where monies are to be drawn out of a customer’s account. This create_wallet command is encapsulated in a proc mgr which will then trigger a corresponding withdraw_account command. What if for some reason the account table is offline? Or for some reason, the transaction falls through like if a new withdrawal policy is enacted system-wide midway?

  1. Just wondering whats the advantage of the proc mgr in commanded apart from compensating actions and workflows as aggregates can emit multiple events from a single command? If i understood correctly, I dont see much difference between the two below:

A saga that listens for a WalletCreated event to trigger a WithdrawAccount command which emits a AccountWithdrawn event:

defmodule MyProj.Sagas.CreateWallet  

  def interested?(%WalletCreated{transfer_uuid: transfer_uuid}) 
  when not is_nil(transfer_uuid) do
    {:start!, transfer_uuid}
  end

  def interested?(%AccountWithdrawn{transfer_uuid: transfer_uuid}) when not is_nil(transfer_uuid) do
    {:continue!, transfer_uuid}
  end

  def handle(%CreateWallet{}, %WalletCreated{transfer_uuid: 
  transfer_uuid, wallet_id: wallet_id, funds_balance: funds_balance, 
  currency: currency}) do
    %WithdrawAccount{
      account_id: account_id,
      transfer_uuid: transfer_uuid,
      withdrawal: Money.to_decimal(funds_balance),
      currency: Cldr.validate_currency(currency) |> elem(1)
    }
  end

  def apply(%CreateWallet{} = saga, %WalletCreated{} = event) do
    %CreateWallet{
      saga
      | transfer_uuid: event.transfer_uuid,
        account_id: event.account_id,
        destination_wallet_id: event.wallet_id,
        funds: event.funds_balance,
        currency: event.currency,
        status: :withdraw_from_account
    }
  end

  def apply(%CreateWallet{} = saga, %WalletWithdrawn{}) do
    %CreateWallet
    {
      saga
      | status: :deposit_into_wallet
    }
  end

vs a single aggregate emitting two events WalletCreated and AccountWithdrawn which will also be projected and produce the same results as above

  def execute(%Wallet{wallet_id: nil}, %CreateWallet{wallet_id: 
  wallet_id, account_id: account_id, funds_balance: funds_balance, 
  currency: currency, transfer_uuid: transfer_uuid} = _create) do
    with validated_funds_balance <- {Money.new(currency, funds_balance)}
    do
      IO.inspect(transfer_uuid)
      %WalletCreated
      {
        wallet_id: wallet_id,
        account_id: account_id,
        funds_balance: validated_funds_balance,
        currency: currency,
        transfer_uuid: transfer_uuid
      }
      %AccountWithdrawn
      {
        account_id: account_id,
        transfer_uuid: transfer_uuid,
        withdrawal: Money.to_decimal(funds_balance),
        currency: Cldr.validate_currency(currency) |> elem(1)
      }
    else
      _ -> {:error, "The wallet cannot be created at this time.}
    end
  end

Many thanks.

Marked As Solved

slashdotdash

slashdotdash

What is the difference between a saga and a process manager?

A process manager is responsible for coordinating multiple aggregates. You can use a process manager to implement the Saga pattern. This is a way of implementing long-lived transactions (spanning minutes, hours, or days) that are written as a sequence of transactions that can be interleaved. All transactions in the sequence complete successfully, or compensating transactions are run to amend a partial execution (rollback on error). The error/3 callback function in a Commanded process manager is where you can handle errors and can execute any rollback commands as applicable.

Distributed Sagas: A Protocol for Coordinating Microservices by Caitie McCaffrey is a really good talk introducing the saga pattern.

In your example since both events are produced by a single aggregate there is no need for a process manager. Emitting two events from the aggregate would be the preferred approach.

Where Next?

Popular in Questions Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39467 209
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 48342 226
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement