1. PostgreSQL 활용 접근 방식
-
IANA 시간대 식별자:
time_zone을 IANA 식별자로 저장하여 PostgreSQL의 내장 시간대 변환 기능을 활용합니다. -
AT TIME ZONE:TIMESTAMP '...' AT TIME ZONE 'Europe/Moscow'와 같이 SQL 쿼리 내에서 시간대 변환을 직접 수행할 수 있습니다. -
UTC 변환:
(timestamp AT TIME ZONE user_timezone) AT TIME ZONE 'UTC'형태로 사용자 시간대의 특정 시간을 UTC로 정확히 변환하여 저장합니다. -
다음 배송 시간 계산:
CURRENT_DATE와INTERVAL '1 day'를 사용하여 오늘 또는 내일의 UTC 배송 시간을 계산하고,NOW() AT TIME ZONE 'UTC'와 비교하여 가장 가까운 미래 시간을 선택합니다. PostgreSQL은 일광 절약 시간(DST) 전환도 자동으로 처리합니다. -
주의사항: 데이터베이스 서버 및 세션의 시간대 설정에 따라 표시되는 UTC 오프셋이 다를 수 있으므로, 데이터베이스를 UTC로 설정하는 것이 가장 좋습니다.
2. Fugit (Ruby Gem) 활용 접근 방식
-
Rails 내 구현: PostgreSQL 방식과 유사하게 Rails 애플리케이션 내에서
Fugitgem을 사용하여 시간대 변환 및 다음 배송 시간을 계산합니다. -
가독성 및 유연성: SQL보다 가독성이 높고, 여러 이벤트 패턴을 하나의 크론(cron) 형식으로 처리할 수 있는 유연성이 있습니다.
-
성능: PostgreSQL 방식에 비해 상대적으로 느릴 수 있습니다.
-
코드 예시:
Fugit.do_parse_cronish(pattern)을 통해 크론 객체를 생성하고,cron.next_time(_reference = Time.current).utc로 다음 UTC 시간을 얻어ActiveJob의set(wait_until: ...)에 활용합니다.
3. 중복 실행 방지 및 기록의 필요성
-
ActiveJob의 한계:
ActiveJob은 작업의 고유한 식별 개념이 부족하여, 사용자 설정 변경 시 동일한 뉴스레터가 여러 번 큐에 추가될 수 있습니다. -
last_delivered_at:newsletter_last_delivered_at컬럼을 사용하여 최근에 발송된 뉴스레터를 건너뛰는 방식으로 중복을 방지할 수 있습니다. -
문제점: 이 방식은 SQL 쿼리와
DeliverNewsletterJob내부 모두에서 중복 확인 로직이 필요하며, 복잡성과 오류 가능성을 증가시킵니다.
4. 모델 기반 접근 방식 (선호)
-
Newsletter 모델 도입:
Account와는 별개로Newsletter모델을 도입하여 뉴스레터 자체를 독립적인 엔티티로 관리합니다. -
상태 관리:
Newsletter모델은pending,delivering,delivered와 같은 상태를 가집니다. -
멱등성 키(Idempotency Key):
idempotency_key를 사용하여deliver_at값이 변경되어 이전 작업이 여전히 큐에 남아있을 경우, 중복 실행을 방지합니다. 작업 실행 시idempotency_key를 확인하여 유효한 작업만 처리합니다. -
다음 뉴스레터 즉시 생성: 현재 뉴스레터가
delivering상태로 전환될 때, 다음 뉴스레터를 즉시pending상태로 생성하여 연속성을 확보합니다. -
코드 구조:
Account모델에has_many :newsletters관계 설정 및deliver_next_newsletter_at메서드 정의.Newsletter모델에enum :state,belongs_to :account,idempotency_key관리 로직,perform_delivery!메서드 구현.NewsletterDeliveryJob은 `Newsletter
perform_delivery!`를 호출.
- 장점:
- 명확한 기록: 사용자별 뉴스레터 수신 기록을 시간 순서대로 추적할 수 있습니다.
- 확장성: 뉴스레터에 기사(Article)를 연결하는 등 추가 기능을 쉽게 구현할 수 있습니다.
- 견고성: 멱등성 키를 통해 중복 배송 문제를 효과적으로 방지합니다.
- 주의사항: ActiveRecord 콜백을 포함하는 복잡한 시스템에서는 미묘한 경합 조건(race conditions)이 발생할 수 있으므로 신중한 설계가 필요합니다.