SQS-Lambda-SNS 연동하기

변현섭·2023년 8월 6일
0
post-custom-banner

지난 포스팅에서 다룬 SQS와 Lambda, SNS를 모두 연동하는 시스템을 설계해보도록 하겠습니다. 이번 포스팅에는 특별히, 제가 프로젝트에서 실제로 사용한 예시를 가져와 보았습니다.

지역 커뮤니티 어플리케이션을 제작하면서 수익 창출의 방법으로 지역광고를 선택하였습니다. 그래서 누구나 쉽게 광고 문의를 넣을 수 있는 서비스를 구현하고자 하였습니다. 그렇게 생각해낸 방법이 본인의 연락처와 광고 내용을 간단히 적어서 제출하면, 저의 휴대폰 번호로 해당 내용의 문자 메시지가 도착하는 것이었습니다.

그럼 저는 문자에 적힌 전화번호로 연락하여 광고주와 구체적인 광고 계약을 진행할 수 있게 될 것입니다. 이번 포스팅에서 다뤄볼 내용이 바로 이 내용이 되겠습니다.

1. SQS

지난번에 이야기했듯, SNS로 메시지를 보내는 서비스는 서울 리전에서 지원되지 않는다. 그러므로 서비스 이용을 위해서는 SQS와 Lambda, SNS 모두 도쿄 리전에서 생성해주어야 한다.

1) SQS 생성하기

먼저 SQS를 생성해보자. SQS 생성 방법은 리전이 도쿄인 점만 빼면, 지난 번과 동일하다. 따라서 아래의 포스팅 내용을 따라 SQS를 생성해주자.
>> SQS 생성하기

2) IAM 정책 권한 확인

IAM > 사용자에 들어가 권한 정책이 아래와 같이 추가 되어있는지 확인한다.

2. Lambda

1) Lambda 함수 생성하기

Lambda도 마찬가지로 도쿄 리전에서 생성해야한다. Lambda 생성 방법도 지난 포스팅에서 다루었으니 아래의 링크를 참조하여 함수 생성까지만 진행하기 바란다.
>> Lambda 생성법
함수 생성이 완료되었으면, 아마 아래와 같은 화면이 되어 있을 것이다.

2) 권한 정책 설정

구성 탭으로 가서 역할 이름 아래에 있는 파란색 링크를 클릭한다.

아래와 같이 권한 정책을 추가해주어야 한다.

3) Lambda에 SQS 트리거 시키기

트리거 추가 버튼을 클릭한다.

SQS를 선택하고, 나머지는 기본값을 유지한 채 추가를 눌러주면 된다.

트리거 설정이 완료되기까지 1분이 조금 안 되는 시간이 걸린다. 아래와 같이 Creating이라고 뜨면 설정 중인 것이고, Enabled라고 떠야 트리거 설정이 완료된 것이다.

4) Lambda 코드 작성

이제 코드만 작성하면 된다. 코드 탭에 들어가 아래의 내용을 입력해주자. 단, 아래의 중괄호로 쓰인 내용은 본인이 적절히 입력해주어야 할 값이다.

import json
import boto3

def send_sms_message(event, context):
    phone = "{본인 전화번호}"
    # SQS 메시지 정보 추출
    records = event.get('Records', [])
    if not records:
        return {
            'statusCode': 400,
            'body': json.dumps('SQS 메시지 정보가 없습니다.')
        }
    
    sqs_message = records[0].get('body')
    if not sqs_message:
        return {
            'statusCode': 400,
            'body': json.dumps('SQS 메시지가 없습니다.')
        }
    # SQS 메시지의 JSON 데이터 추출
    try:
        data = json.loads(sqs_message)
        phoneNumber = data.get('phoneNumber')
        content = data.get('content')
    except Exception as e:
        return {
            'statusCode': 400,
            'body': json.dumps('SQS 메시지 파싱 오류: ' + str(e))
        }
    # 전화번호와 내용 확인 및 처리
    if phoneNumber and content:
        print("전화번호: ", phoneNumber)
        print("내용: ", content)

    sns = boto3.client('sns', region_name='ap-northeast-1', aws_access_key_id='{IAM Access Key}',
                   aws_secret_access_key='{IAM Secret Key}')
    
    try:
        print(phoneNumber + " / " + content )
        response = sns.publish(
            PhoneNumber=phone,
            Message=phoneNumber + " / " + content 
        )
        print(response)
        return {
            'statusCode': 200,
            'body': json.dumps('메시지가 성공적으로 전송되었습니다.')
        }
    except Exception as e:
        error_message = str(e)
        print(error_message)
        return {
            'statusCode': 500,
            'body': json.dumps('메시지 전송 중 오류가 발생하였습니다. 에러 메시지: ' + error_message)
        }

당연한 이야기이지만, 본인의 전화번호는 AWS SNS에 등록이 되어있어야 하며, 전화번호의 형식은 전화번호가 010-1234-5678이라고 했을 때, +821012345678이 되어야 한다. 전화번호를 추가하는 방법이 궁금하다면 이전 포스팅의 내용을 참고하라.
>> SNS에 전화번호 추가하기

3. Cloud Watch 사용하기

1) Cloud Watch를 사용해야 하는 이유

사실 이 서비스를 구현하기까지 정말 많은 시간을 허비했다. SQS에 Json 파일이 잘 올라가는 것을 확인했고, 람다 함수 테스트도 잘 동작하는데, 왜인지 모르게 SQS에 메시지를 올려도 휴대폰에 메시지가 도착하지 않았다.

만약 인텔리제이나, VS Code에서 작성한 코드였다면 어디서 에러가 발생하고 있는지를 금방 알 수 있었을텐데, 람다에서 코드를 실행하다보니, 어디에서 문제가 발생하는지조차 알기 어려웠다.

그래서 실제로 구글링도 수차례 해보았고, 권한문제인가 싶어 권한도 추가해보았지만, 번번이 실패하였다. 그러던 중 알게 된 AWS 서비스가 바로 Cloud Watch이다.

Cloud Watch에서 로그를 조회해보니, phoneNumber와 content에 none이 할당되어 있었다. 처음 코드를 작성했을 때는 당연히 SQS에 넘겨준 JSON 파일이 그대로 넘어올 것이라 생각하여 아래와 같이 값을 할당해주었다.

phoneNumber = event.get('phoneNumber')
msg = event.get('content')

그런데, 실제로 SQS에서 넘어온 event 객체를 print로 출력해보니 결과가 아래와 같았다.

분명히 SQS에서 확인한 값은 아래와 같은 JSON 형식이었는데, 예상보다 훨씬 복잡한 값이 event에 할당되어 있었던 것이다.

{
    "phoneNumber" : "010-1234-9876",
    "content" : "인천시 부평구 한우마을 광고 문의합니다!"
}

즉, JSON 파싱 과정에서 문제가 발생해 문자 메시지가 오지 않았던 것이다. 에러의 원인을 파악하고 나니, 코드를 수정하는 데에 어려움이 없었다.

2) Cloud Watch 사용법

만약 본인이 작성한 람다 함수가 잘 동작하지 않을 경우, Cloud Watch를 통해 로그를 확인할 수 있다. Cloud Watch 서비스에 들어간 후 로그 그룹을 클릭하면, 아래와 같은 화면이 나온다.

Cloud Watch의 로그 그룹은 람다 메서드를 실행하면 저절로 생성된다. 본인이 원하는 람다 함수를 선택해 들어가보면 아래와 같이 함수 실행 history가 나온다.

history를 클릭하여 에러 로그를 확인할 수 있다. 아래는 핸들러 메서드의 이름을 제대로 설정하지 않아 람다 함수가 제대로 실행되지 못했음을 알려주고 있다.

디버깅에 있어 유용한 방법은 코드의 중간 중간에 print("1"), print("2"), ...을 넣고 실행한 뒤, Cloud Watch를 통해 로그를 확인하는 것이다. 이 방법은 어디까지 실행되다가 멈추었는지 확인하기에 매우 유용하다. 또는 내가 생각했던 변수에 값이 제대로 할당되었는지 확인하기 위해 print(value)를 중간에 삽입해보는 것도 좋은 방법이다.

4. API

1) 코드 작성하기

아래는 광고 문의를 넣기 위해 광고주가 사용할 API의 Controller 코드이다.

참고로, PostInquiryReq는 연락처와 광고 내용을 받는 DTO이다. 즉, 광고주의 연락처와 광고 내용을 받고 있는 것이다.

아래는 Service 코드이다. queueUrl에는 본인의 SQS Url을 넣으면 된다.

2) API Test

이제 포스트맨에서 해당 API를 호출하여 SQS로 광고문의를 올리면, SQS에 트리거된 람다가 SQS에서 데이터를 가져와 나의 휴대폰으로 문자 메시지를 보내는 함수를 실행할 것이다. 그 결과, 휴대폰 메시지로 광고주의 연락처와 광고 내용이 도착해야 한다. API를 호출해보자.

그리고 5초 정도 기다리면, 아래와 같이 문자 메시지가 도착한다.

함수가 잘 실행되었음을 Cloud Watch에서도 확인할 수 있다.

profile
Java Spring, Android Kotlin, Node.js, ML/DL 개발을 공부하는 인하대학교 정보통신공학과 학생입니다.
post-custom-banner

0개의 댓글