관심분야/클라우드

#6 Lambda Function 작성 - AWS 음성지원 서비스를 활용한 신문 읽어주는 프로젝트

뱅노 2019. 11. 23. 14:53

이제까지 DynamoDB와 Lambda를 Trigger 연결하였다. 이제 Trigger 연결된 Lambda에 DyanamoDB Insert 데이터가 잘 들어오는지 확인을 하고 Polly로 원하는 데이터를 보낼 수 있도록 데이터 정제 작업을 진행하도록 하겠다.

빨간색 네모칸 영역 중 Lambda 영역이다. 처음에 Lambda를 생성해 보면 아래와 같이 기본적으로 함수가 생성된다. Lambda 소스 작성방법은 여러 가지가 있다. 로컬에서 작성 후 .zip파일로 올릴 수도 있고 S3에 적재해서 Trigger로 가지고 와도 된다. 나 같은 경우는 그냥 Web화면에서 바로 작업을 하였다. 참고로 Lambda도 로컬에 환경을 만들 수 있다고 한다. 나도 아직 해보지는 않다.

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

다시 본론으로 돌아와서 인자값으로는 event와 context가 나오게 된다. event 인자 값에서는 Lambda로 들어오는 데이터들을 확인해 볼 수 있다. context 인자 값의 경우 현재 Lambda 함수의 메모리 참조값이 나온다. 따라서 Lambda 함수의 정보들을 가지고 올 수 있는 인자 값이다.

아래 링크로 들어가면 context 인자 값에서 얻을 수 있는 값의 설명을 하고 있다.

 

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/python-context-object.html

 

AWS Lambda 콘텍스트 객체(Python) - AWS Lambda

AWS Lambda 콘텍스트 객체(Python) Lambda은 함수를 실행할 때 컨텍스트 객체를 핸들러로 전달합니다. 이 객체는 호출, 함수 및 실행 환경에 관한 정보를 제공하는 메서드 및 속성들을 제공합니다. 컨텍스트 메서드 get_remaining_time_in_millis – 실행 시간이 초과되기 전에 남은 시간(밀리초)을 반환합니다. 컨텍스트 속성 function_name – Lambda 함수의 이름 function_version – 함수의 버전

docs.aws.amazon.com

나의 경우에는 현재 event 인자 값만 가지고 사용해도 된다. event 인자 값에 어떠한 값이 나오는지 확인하게 위해서 print함수를 호출해서 확인을 해본다.

import json

def lambda_handler(event, context):
    # TODO implement

    print('event {}'.format(event))
   
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

위와 같이 print함수를 호출하고 이전에 만들었던 crawling 프로그램으로 DynamoDB에 데이터를 Insert 시켜본다. 그러면 정상적으로 동작을 했는지 확인을 해봐야 한다. 정상 동작에 대한 확인을 하기 위해서는 Amazon CloudWatch 섹션으로 이동해서 확인을 해본다.

Amazon CloudWatch 좌측 메뉴 중 [로그] 메뉴에 진입하게 되면 내가 만들어서 호출한 "setNewsInfo_test"라는 함수의 로그가 보이기 된다. setNewsInfo_test 로그를 클릭해준다.

로그를 확인해 보면 내가 DynamoDB에 Insert 한 데이터가 작성되어 있는 것을 확인할 수 있다.(event 인자 값은 위 데이터보다 더 상세하게 앞에 다른 데이터가 있다. 그러나 해당 데이터는 나의 AWS 고유 정보라서 제외시켰다.) 일단 데이터를 확인했으니, 테스트를 진행하면서 내가 원하는 데이터를 추출할 수 있도록 하자. 우선 event 인자 값에 나오는 데이터는 JSON형식이다. 데이터가 워낙 많기 때문에 보기가 많이 힘들다. 아래의 링크로 가서 보면 JSON형태의 값을 정리해서 한눈에 볼 수 있도록 도와주는 사이트가 있다.

http://jsonviewer.stack.hu/

 

Online JSON Viewer

 

jsonviewer.stack.hu

위 사이트에 Lamdba event에서 나온 JSON 데이터를 Copy 해 놓고 JSON 구조를 확인한다.

 

그다음 위 형태에 맞게 아래와 같이 소스를 작성해 준다.

import json

def lambda_handler(event, context):
    # TODO implement
    
    print('DynamoDB Insert trigger')
    
    polly_newimage_data = event['Records'][0]['dynamodb']
        
    polly_newimage_data = polly_newimage_data['NewImage']
    
    polly_data = polly_newimage_data['CONTENT']['S']
    
    print('polly_data {}'.format(polly_data))
    
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

이제 테스트를 해봐야 한다. 테스트는 아까와 동일하게 테스트를 안 할 것이다. 왜냐면 DynamoDB에 읽기, 쓰기의 트렌젝션이 발생할 때마다 비용이 청구가 된다. 비용절감을 위해서는 Lambda에서 자체적으로 테스트를 진행하고 난 후 테스트를 해볼 생각이다.

위에 보면 [테스트] 버튼 옆에 SelectBox가 존재한다. 테스트 이벤트를 설정할 수 있는 곳이다. "테스트 이벤트 구성"을 클릭해 준다. 처음에는 아무것도 없어서 신규로 작성하도록 되어 있을 것이다.

신규 작성을 하게 되면 Hello World 템플릿에서 작성하도록 나온다. JSON 형태로 Lambda 테스트 데이터를 생성하면 된다. 아까 내가 print 함수 호출로 로그에 작성해 놓은 event 인자 값을 신규 테스트 이벤트로 작성한다.(그냥 로그 내용을 복사, 붙여놓기 하면 된다.) 모두 작성하고 난 후 [Create] 버튼을 클릭해준다. 테스트 이벤트를 생성한 후 [테스트] 버튼을 클릭해준다. 다음 CloudWatch로 이동해서 로그를 확인한다. 아마 정상적으로 작동을 할 것이다. 이제 DynamoDB에 Insert 테스트를 하기 위해서 아까 실행시킨 crawling 프로그램을 실행시킨다.

 

정상적으로 작동되지 않고 에러가 발생할 것이다. 에러 내용은 다음과 같다.

[NewImage]라는 key값이 존재하지 않는다는 내용이다. "이게 뭔 소리냐... 분명히 처음에는 있었는데..." 혹시 몰라서 DynamoDB에 적재되어 있는 데이터를 지우고 해 봐도 동일한 에러가 발생하였다. 확인해 보니 [NewImage]라는 key값이 [OldImage]라고 변경이 되었다. 그리고 DynamoDB에 데이터를 삭제를 해도 NewImage로 key값이 되돌아오지 않는다. Lambda가 DynamoDB 데이터를 Trigger 하여 가져올 때 DynamoDB의 파티션 키와 정렬 키를 확인해서 이전에 동일하게 없으면 NewImage, 있으면 OldImage로 결정하는 것 같다. 여하튼 아래와 같이 소스를 조금 수정을 하였다.

import json

def lambda_handler(event, context):
    # TODO implement
    
    print('DynamoDB Insert trigger')
    
    polly_newimage_data = event['Records'][0]['dynamodb']
    
    # content 영역의 key가 old인지 new인지 확인한다.
    image_key = 'OldImage'
    if 'NewImage' in polly_newimage_data :
        image_key = 'NewImage'
        
    polly_newimage_data = polly_newimage_data[image_key]
    
    polly_data = polly_newimage_data['CONTENT']['S']
    
    print('polly_data {}'.format(polly_data))
    
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

참고로 Python3 버전부터 딕셔너리형에서 has_key 함수 사용을 못한다. 그래서 if문으로 한번 확인하는 로직이 필요하다. 위와 같이 소스를 작성하게 되면 poll_data 변수에 내가 음성변환을 시키고 싶은 데이터가 추출되게 된다.

 

다음에는 polly로 데이터를 보내서 음성변환을 시키는 작업을 진행해 보도록 하겠다.