Last active
March 22, 2018 12:14
-
-
Save AndrewDryga/077dadc2afd8c20a0c26023f3ef58397 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment