CRM 중 하나로 서비스를 이용한 고객에게 자동 메시지를 발송하는 방법이 있습니다. 우리 서비스가 플랫폼 형태라고 가정하면 상품을 제공하는 파트너, 서비스를 이용하는 유저가 있을 것입니다. 이때 자동 메시지 기능의 요구사항을 간단하게 표현하면 다음과 같을 것입니다.
파트너는 메시지를 자유롭게 구성하여 발송할 수 있다.
- 메시지 내용
- 유저가 구매한 이후 메시지를 보내는 기간과 시간대 (ex. 2일 후 오전 7시 발송)
이때, 고민할 것들은 다음 3가지 정도가 있을 것 같습니다.
- Reminder (파트너가 작성한 자동 메시지 템플릿 저장) 모델을 어디에 두어야 할까?
- 파트너가 관리를 하는 것이니까 파트너 컨텍스트에 둔다?
- 음료마다 보내야 할 메시지가 있으니까 상품 컨텍스트에 둔다?
- Reminder, Scheduler 중 누가 누구를 참조해야 할까?
- Scheduler (AWS EventBridge Scheduler 에 메시지를 등록) 을 동기 방식과 비동기 방식 중 무엇으로 구현해야 할까?
도메인 (1, 2번 고민)
Scheduler 객체
먼저, 객체의 책임에 대해서 생각해보겠습니다. Scheduler 객체는 전달받은 메시지를 AWS EventBridge Scheduler에 등록합니다. 그 메시지가 api 호출을 통해 직접 전달이 되었든, SNS-SQS 방식으로 비동기로 전달이 되었든 그저 전달받은 메시지를 아마존 스케줄러에 등록합니다.
이어서 객체의 협력에 대해 생각해보겠습니다. 서비스에 알림함이 있다면 스케줄러를 통해 발송한 메시지를 저장해야 하고, 자동 메시지 발송 기능이 있다면 스케줄러 등록을 해야 하기 때문에 스케줄러 모델은 알림함과 리마인더 모델과 협력을 해야 합니다.
그리고 필요한 기능을 생각해보면, 파트너가 예정된 메시지가 무엇이고 발송이 제대로 잘 되었는지 확인하고, 직접 등록을 할 수 있게 해야 하기에 Scheduler를 파트너 컨텍스트에 위치해야 합니다. 그런데 협력을 생각해보면 메시지라는 컨텍스트를 새로 구성하는 것도 좋을 것 같네요.
Reminder 객체
객체의 책임은 파트너가 작성한 자동 메시지 템플릿을 저장하는 것입니다. 그리고 이것을 유저에게 보내야 하기 때문에 Scheduler와 협력을 통해 메시지를 등록해야 합니다. Reminder가 Scheduler를 참조해서 메시지를 보내는 구조입니다. 그렇다면 Scheduler와 동일하게 파트너 컨텍스트에 위치해야 할까요?
요구사항을 다시 살펴보겠습니다. 자동 메시지는 상품별로 구성이 됩니다. 즉, 작성이야 파트너가 하겠지만 개념적으로는 핵심 기준인 상품과 더 밀접하게 연관되어 있는 것이죠. 그래서 Reminder는 Product 컨텍스트에 위치시켰습니다.
시퀀스 다이어그램 (3번 고민)
동기, 비동기 방식을 선택할 때는 크게 2가지를 고려해볼 수 있습니다.
- 처리 속도
- 실패 케이스 대응
동기적으로 구현할 경우, 모든 기능들이 완료될 때까지 기다려야 합니다. 파트너가 방문완료 처리를 했을 때 Reminder를 조회하고, Scheduler를 호출하고 AWS EventBridge에 등록하는 것까지 기다려야 합니다. 등록할 메시지가 많아질 경우 속도가 느려질 것인데 UX 측면에서 파트너는 이것을 기다릴 이유가 없습니다. 또한 모든 처리를 트랜잭션으로 구성하는 과정이 어려울 수 있습니다. 다른 컨텍스트에 도메인 모듈로 위치하는 게 아닐 경우 api를 호출하여 처리할텐데, 실패한 경우 이를 보완하는 api를 호출해야 하고, aws 서비스를 이용함에 있어서 롤백이 어려울 수 있습니다.
그래서 AWS SNS, SQS 를 활용하여 비동기적으로 구성하기로 결정했습니다. 파트너가 요청을 기다릴 필요가 없습니다. 만약 Queue를 여러개 사용한다면 pub-sub 구조를 통해 병렬적으로 처리하는 것도 장점이 될 수 있습니다. 또한, 자체적인 재시도 동작을 통해 실패에 대한 관리를 수월하게 할 수 있습니다. SNS는 DeliveryRetryPolicy 를 통해 재시도를 하고, SQS도 Visibility Timeout을 통해 메시지 처리 실패 시 메시지가 대기열로 들어가며 재시도를 합니다. SQS의 경우, DLQ(Dead Letter Queue) 설정을 통해 재시도 횟수를 초과한 메시지를 따로 저장하여 처리할 수도 있습니다.
AWS 주의점
SAM과 콘솔을 활용해서 SNS, SQS, EventBridge를 이용할 때 주의해야 할 점을 정리해보겠습니다.
SQS 정책 설정
sns 에서 주제를 만들고, sqs 에서 대기열을 만들고 구독을 설정하고 테스트를 하면 대기열에 메시지가 가지 않는 경우가 있습니다. 이때는 SQS 콘솔에서 대기열 정책을 확인해보세요.
기본 정책은 아래와 같을 겁니다. 그런데 SNS가 대기열에 메시지를 보낼 수 있도록 정책을 설정해줘야 합니다.
{
"Version": "2012-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Sid": "__owner_statement",
"Effect": "Allow",
"Principal": {
"AWS": "your_aws_id"
},
"Action": [
"SQS:*"
],
"Resource": "arn:aws:sqs:ap-northeast-2:your_aws_id:test"
}
]
}
변경된 정책은 다음과 같습니다. sns 서비스에 대해("Service": "sns.amazonaws.com") sqs에 메시지를 보내는("Action": "sqs:SendMessage") 행동을 설정해주었습니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:ap-northeast-2:your_aws_id:test_sqs",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:sns:ap-northeast-2:your_aws_id:test_sns"
}
}
}
]
}
SAM 람다의 시간 30초 이하로 설정
SQS가 재시도를 실행하는 Visibility Timeout은 30초입니다. SAM 템플릿을 사용할 경우 리소스 함수의 timeout 을 30초보다 5~10초 정도 작게 설정해주세요
.
SNS MessageGroupId 128자 이하로 설정
SNS를 FIFO로 사용할 경우 옵션으로 MessageGroupId를 설정할 수 있습니다. 이는 그룹을 지정하여, 그룹 단위로 순서를 보장하면서 그룹 간에 병렬처리를 해주게 하는 역할을 하는 옵션입니다. 만약 자세하게 설정하기 위해 다양한 정보를 담아서 그룹 아이디를 설정했다면 128자를 넘어간다는 에러를 만날 수 있으니 참고하세요. 그리고 혹시 template literals 를 사용할 경우, 객체가 들어가진 않았는지도 점검해주세요.
람다가 활용하는 aws 서비스에 대한 권한 설정 잘하기
기능을 구현하는 일련의 로직에서 사용되는 aws의 권한을 추가해주세요. 안그러면 권한이 없다는 에러를 맞습니다.
TestFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: test-function
CodeUri: test-function
Policies:
- AWSLambdaRole
- AmazonSQSFullAccess
- AmazonEventBridgeSchedulerFullAccess
'Insight > 회고' 카테고리의 다른 글
[Fangle] K-pop 글로벌 커뮤니티 - 짤 기반 소통 & 입덕 아카이브 (0) | 2025.03.05 |
---|---|
[업무회고] 예약 모델 설계 & 배치로직 작성 디테일 (0) | 2025.02.19 |
[업무회고] RIZZ 2.0 상담 모델 설계 (0) | 2025.01.18 |
[업무회고] RIZZ 3.0 알림함 & 메시지 예약 발송 기능 설계 및 구현 (0) | 2025.01.14 |
[업무회고] RIZZ 3.0 유저의 병원별 추천 코드를 통한 맴버십 관리 (0) | 2025.01.12 |