Skip to content

Instantly share code, notes, and snippets.

@AndrewDryga
Last active May 20, 2018 12:47
Show Gist options
  • Save AndrewDryga/0a13318d4c4a7dafd0db35bf338dd6bd to your computer and use it in GitHub Desktop.
Save AndrewDryga/0a13318d4c4a7dafd0db35bf338dd6bd to your computer and use it in GitHub Desktop.
Sage: Business Logic Getting Worse
defmodule MyApp.Domain.User.SignUp do
def create_and_subscribe_user(attrs) do
Repo.transaction(fn ->
with {:ok, user} <- create_user(attrs),
{:ok, plans} <- fetch_subscription_plans(attrs),
{:ok, charge} <- charge_card(user, subscription),
{:ok, subscription} <- create_subscription(user, plan, attrs),
{:ok, _delivery} <- schedule_delivery(user, subscription, attrs),
{:ok, _receipt} <- send_email_receipt(user, subscription, attrs),
{:ok, user} <- update_user(user, %{subscription: subscription}) do
{:ok, user}
else
{:error, {:charge_failed, _reason} = error} ->
# First problem: charge is not available here
:ok = refund(charge)
{:error, error}
{:error, {:create_subscription, _reason} = error} ->
# Second problem: growing list of compensations
:ok = refund(charge)
:ok = delete_subscription(subscription)
{:error, error}
# Third problem: how to decide when we should be sending another email or
# at which stage we've failed?
other ->
# Will rollback transaction on all other errors
:ok = ensure_deleted(fn -> refund(charge) end)
:ok = ensure_deleted(fn -> delete_subscription(subscription) end)
:ok = ensure_deleted(fn -> delete_delivery_from_schedule(delivery) end)
other
end
end)
end
defp ensure_deleted(cb) do
case cb.() do
:ok -> :ok
{:error, :not_found} -> :ok
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment