Skip to main content

Command Palette

Search for a command to run...

Ash Oban

Published
•2 min read•View as Markdown

최근 작업중에 이메일 발송을 처리해야 했다.
after_action 에 이마일 발송을 고려했는데 최종적으로는 AshOban 을 사용했다.

AshOban이 뭔가?

Ash Framework와 Oban을 이어주는 라이브러리다. 백그라운드 job을 Ash 스타일로 쓸 수 있게 해준다.

멤버 초대 이메일 보내기

클럽에 새 멤버를 초대하면 이메일을 보내야 하는 상황이다. 이걸 어떻게 처리할까?

Action Hook으로 하면:

  • 사용자가 서버에서 이메일 발송을 위한 외부요청을 처리하는 것을 기다려야 함

  • 이메일 발송에 실패하면 멤버 생성도 실패함

AshOban으로 하면:

after_action fn _changeset, membership, context ->
  # 이메일을 나중에 보내도록 예약
  AshOban.schedule(SendInvitationEmail, %{membership_id: membership.id})
  {:ok, membership}
end

# Job 정의
oban do
  job SendInvitationEmail do
    def perform(%{args: %{"membership_id" => membership_id}}, context) do
      membership = Ash.get!(Membership, membership_id) |> Ash.load!([:user, :club])
      Emails.send_invitation_email(membership.user, membership.club)
    end
  end
end
  • 사용자가 기다릴 필요 없음 (빠름)

  • 이메일 실패해도 멤버 생성은 성공

  • 실패하면 자동으로 재시도

  • Ash context(권한, tenant 등)가 자동으로 넘어감

왜 AshOban 을 사용하나?

일반 Oban은 actor나 tenant 정보를 수동으로 넘겨야 하는데, AshOban은 알아서 해준다. Multi-tenancy 쓰면 특히 편하다. 그리고 이메일 서버가 다운되어도 알아서 나중에 다시 시도한다.

언제 써야 할까?

AshOban 써야 하는 경우:

  • 이메일, SMS 같은 외부 서비스 호출

  • 시간 오래 걸리는 작업

  • 실패해도 재시도해야 하는 작업

Action Hook으로도 충분한 경우:

  • 간단한 데이터 변환, 로깅

  • 실패하면 전체를 롤백해야 하는 경우

주의할 점

Struct 대신 ID만 넘기자. struct는 직렬화가 안된다:

# 안됨
AshOban.schedule(MyJob, %{membership: membership})

# 됨
AshOban.schedule(MyJob, %{membership_id: membership.id})

정리

이메일 발송 같은 외부 서비스 연동은 Oban 을 통해 백그라운드로 처리하는게 좋은 것 같다. 사용자 경험도 개선할 수 있다.

More from this blog

Ash Typescript

TL;DRElixir의 Ash Framework로 정의한 리소스를 TypeScript와 바로 연결해 주는 툴.백엔드 스펙을 따로 문서화하지 않아도 타입 안정성과 동기화를 자동으로 보장한다. 왜 사용하는가? Elixir로 백엔드를, TypeScript로 프런트엔드를 작성하다 보면 변경되는 API 스펙을 항상 동기화된 상태로 관리하기 쉽지 않다.결국 동기화를 위해서는 Graphql 을 사용하거나, 별도의 툴이 필요하다.AshTypescript ...

Sep 28, 20253 min read

Ash Reactor

TLDR; Reactor는 복잡한 워크플로우를 단계별로 정의하고 실행하는 라이브러리다. 각 단계가 독립적으로 돌아가며, 병렬 처리와 에러 핸들링도 쉽게 할 수 있다. 왜 쓸까? 프로젝트에서 "데이터 조회 → 가공 → 외부 API 호출 → 저장" 같은 복잡한 로직을 처리할 때가 있다.이런걸 그냥 함수로 쭉 연결하면 코드가 복잡해지고 에러 처리도 어려워진다. Reactor를 쓰면 각 단계를 명확히 분리하고 선언적으로 워크플로우를 관리할 수 있다. ...

Sep 21, 20254 min read

Ash StateMachine

TLDR; Ash StateMachine 은 상태 변경이 가능한 케이스를 명시하고, 미리 선언된 상태 변경만 가능하도록 한다. 왜 쓸까? 예를 들면, “새로 생성 → 진행 중 → 완료” 처럼 정해진 workflow 가 있다면, 로직으로 if/else 를 사용하는 것보다 상태머신으로 선언해 두는 게 안전하고 읽기 쉽다. 예제: Task 요구사항: 기본 상태는 :new :start 액션이 :new → :in_progress :finish ...

Sep 14, 20252 min read

kkbz.hop

14 posts