chemist

chemist

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.

Showing Posts 1 to 2

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.

chemist

chemist OP

The talk was illuminating. Many thanks :slight_smile:

I hope my sharing helps the community here

I managed to figure out the best outcome - and my experience is that for more complex workflows - a process manager is useful. But for simply emitting multiple events without the need for compensating actions, the overhead and additional complexity of a PM/saga isn’t worth it.

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews