Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- defmodule SageExample do
- import Sage
- require Logger
- # It is better to build Saga struct in a module attribute,
- # we don't need to spend resources each time we want to execute it
- @create_and_subscribe_user_sage
- new()
- |> run(:user, &create_user/2)
- |> run(:plans, &fetch_subscription_plans/2)
- |> run(:subscription, &create_subscription/2, &delete_subscription/3)
- |> run_async(:delivery, &schedule_delivery/2, &delete_delivery_from_schedule/3)
- |> run_async(:receipt, &send_email_receipt/2, &send_excuse_for_email_receipt/3)
- |> run(:update_user, &set_plan_for_a_user/2)
- |> finally(&acknowledge_job/2)
- def create_and_subscribe_user(attrs) do
- Sage.transaction(@create_and_subscribe_user_sage, Repo, attrs)
- end
- # Transaction callback receives previously created effects
- # and attributes passed to `execute/2` or `transaction/3`
- def create_user(_effects, attrs) do
- # We can use raw insert if we expect Sage to be wrapped in a transaction,
- # because DB-related effects would be compensated on transaction rollback
- Repo.insert(%SageExample.User{login: attrs["login"], password: attrs["password"]})
- end
- # .. other transaction callbacks
- # Steps have access to effects created on previous steps
- def create_subscription(%{user: user}, attrs) do
- BillingAPI.subscribe_user(user, plan: attrs["plan"])
- end
- # If we failed on this step because of timeout of external service, let's keep retrying
- def delete_subscription(nil, {:subscription, _reason}, _attrs) do
- {:retry, retry_limit: 5}
- end
- # Cleanup effect created by create_subscription/2
- def delete_subscription(_subscription_or_nil, _errorred_step_name_and_reason, _attrs) do
- Logger.error("Failed to create subscription because of #{inspect(reason)}")
- # We must delete all subscriptions for a newly created user,
- # because we don't know if it was actually created on third-party service or not
- BillingAPI.Subscription.delete_all_by_email(attrs["email"])
- end
- # .. other transaction callbacks
- def acknowledge_job(:ok, attrs) do
- Logger.info("Successfully created user #{attrs["email"]}")
- end
- def acknowledge_job(_error, attrs) do
- Logger.warn("Failed to create user #{attrs["email"]}")
- end
- end
Add Comment
Please, Sign In to add comment