[AWS][SAM][강의노트] 다양한 시그니처의 람다 작성해보기

컴퓨터공학/서버리스

2022. 03. 11.

다양한 시그니쳐의 람다 작성 해보기

다양한 시그니처를 갖는 람다 핸들러를 작성해 보겠습니다.

각 메서드를 작성하면 테스트를 위해 template.yaml의 핸들러 지정을 바꿔줍니다.

그리고 sam build & sam local invoke --event events/events.json 을 사용하여 테스트를 진행합니다.

float → boolean

public boolean getNumber(float number) {
    return number> 100000;
}

events.json

이벤트에 아무 숫자를 입력하자.

1234.4444

result

false

list → list

public List<Integer> getScores(List<String> names) {
    Map<String, Integer> studentScores = new HashMap<String, Integer>();
    studentScores.put("John", 90);
    studentScores.put("Bob", 80);
    studentScores.put("Ahmed", 100);

    return names.stream()
            .map(student-> studentScores.get(student))
            .filter(it-> it != null)
            .collect(Collectors.toList());
}

events.json

이벤트에 JSON Array를 정의하자.

["John", "Bob", "Ahmed"]

result

JSON Array가 반환되었다.

[90,80,100]

map<string, int> → void

public void saveEmployeeData(Map<String, Integer> empData) {
    // do nothing
}

events.json

이벤트에 JSON Array를 정의하자.

{
  "John": 1234,
  "Bharath": 100000
}

result

자바 메서드 반환이 void이었더니 null 로 반환되었다.

null

void → map<string, list>

public Map<String, List<Integer>> getStudentScores() {
    Map<String, List<Integer>> studentScores = new HashMap<String, List<Integer>>();
    studentScores.put("John", Arrays.asList(80, 90, 100));
    studentScores.put("Bob", Arrays.asList(10, 15, 22));
    studentScores.put("Ahmed", Arrays.asList(33, 66, 99));
    return studentScores;
}

events.json

이벤트에 아무것도 줄 필요 없다.

result

학생 이름을 key, 그들의 점수 리스트를 value로 하는 JSON 객체가 반환되었다.

{"Ahmed":[33,66,99],"Bob":[10,15,22],"John":[80,90,100]}

POJO → POJO

SNS, S3, API Gateway등이 람다를 호출하여 이벤트를 넘겨주면 특정 자바 POJO에 매핑된 형태로 람다 메서드에 도착합니다.

Hello World 템플릿은 API 게이트웨이가 쏴 주는 APIGatewayProxyRequestEvent 타입의 POJO를 받아내는 람다 메서드를 갖고 있었습니다.

아무튼 계속 진행...

public ClinicalData getClinical(Patient patient) {
    System.out.println(patient);
    ClinicalData clinicalData = new ClinicalData();
    clinicalData.setBp("80/120");
    clinicalData.setHeartRate("80");
    return clinicalData;
}

pojos

public class Patient {
    private String name;
    private String ssn;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSsn() {
        return ssn;
    }

    public void setSsn(String ssn) {
        this.ssn = ssn;
    }

    @Override
    public String toString() {
        return "Patient{" +
                "name='" + name + '\'' +
                ", ssn='" + ssn + '\'' +
                '}';
    }
}

public class ClinicalData {
    private String bp;
    private String heartRate;

    public String getBp() {
        return bp;
    }

    public void setBp(String bp) {
        this.bp = bp;
    }

    public String getHeartRate() {
        return heartRate;
    }

    public void setHeartRate(String heartRate) {
        this.heartRate = heartRate;
    }
}

events.json

Patient POJO 형식에 맞춘 JSON을 이벤트로 넣자.

{"name": "John", "ssn": "123444"}

result

ClinicalData POJO 형식에 맞춘 JSON이 반환되었다.

{"bp":"80/120","heartRate":"80"}

inpustream, outputstream → void

람다는 인풋 스트림에 반응할 수 있습니다. 그리고 아웃풋 스트림에 결과물을 써줄 수 있습니다.

스트림을 입력, 출력으로 사용하면 람다를 매우 동적으로 활용할 수 있습니다. 스트림 타입은 Map보다 훨씬 유연한 타입입니다.

 

람다 메서드의 이런 시그니쳐를 알아본 람다 서비스 및 람다 런타임은, 알아서 스트림을 형태로 인자를 주입하며, 스트림의 close()에 대해선 개발자가 신경 쓰지 않아도 됩니다.


 * 테스트로는 영어 문자열을 입력 받아 소문자로 변환하여 되돌려 보낼 겁니다.

/**
 * input 인풋 스트림에서 받은 데이터를 소문자 변환해서 output 아웃풋 스트림에 씁니다.
 * 이 람다 메서드의 시그니쳐를 알아본 람다 서비스와 람다 런타임이 알아서 스트림을 생성하여 주입하며, close()에 대해 신경 쓰지 않아도 됩니다.
 * 테스트 이벤트는 영어 문자열을 입력 받아 소문자로 변환하여 되돌려 보낼 겁니다.
 * @param input 임의 형식을 갖는 데이터 스트림. POJO 매핑을 쓰는 람다와 비교하여 매우 유연한 입력 타입입니다.
 * @param outputStream 임의 형식을 갖는 출력 스트림.
 */
public void getOutput(InputStream input, OutputStream outputStream) throws IOException {
    int data;
    while ((data = input.read()) != -1) {
        outputStream.write(Character.toLowerCase(data));
    }
}

events.json

임의 값을 입력하자. 인풋스트림으로 제공될 값이기 때문에 “” 로 묶는 작업도 하지 않았다.

Huh,,, I have no IDEA!

result

인풋 스트림(문자열 스트림)을 읽어서 그것을 소문자 변환한 문자열을 획득한다.

huh,,,, i have no idea!

Context 객체

AWS Lambda 컨텍스트 객체(Java)

람다 호출이 남긴 로그


END RequestId: 6c87a66c-31b5-4d0c-927b-c202c54126f7
REPORT RequestId: 6c87a66c-31b5-4d0c-927b-c202c54126f7  
Init Duration: 0.18 ms  
Duration: 322.19 ms     
Billed Duration: 323 ms Memory Size: 256 MB     
Max Memory Used: 256 MB 

콘솔에서 람다 호출이 남긴 로그를 보면

  • RequestID (→람다 요청은 매번 ID를 갖는다)
  • Version (→ 람다 함수의 버젼)
  • 실행 정보 및 과금 정보

이러한 유형의 정보들이 출력됩니다.

자바 런타임에서 이 값들이 람다 코어 라이브러리 [aws-lambda-java-core] 의 Context 객체에 담겨지는데

우리 람다에게 인자로 주입시켜서 각종 메타데이터를 뽑아 먹을 수 있습니다.

import com.amazonaws.services.lambda.runtime.Context;

public void getOutput(InputStream input, OutputStream outputStream, Context context) throws IOException {
    System.out.println(context.getAwsRequestId());
    System.out.println(context.getFunctionName());
    System.out.println(context.getRemainingTimeInMillis());
    System.out.println(context.getMemoryLimitInMB());
    System.out.println(context.getLogGroupName());

    int data;
    while ((data = input.read()) != -1) {
        outputStream.write(Character.toLowerCase(data));
    }
}

result

인풋 스트림(문자열 스트림)을 읽어서 그것을 소문자 변환한 문자열을 획득한다.

cf8065ed-ff19-4e66-ae54-195d9c6b976b # aws request id
HelloWorldFunction # function name
2997 # remaining time in millis
256 # memory lmits (MB)
aws/lambda/HelloWorldFunction # its cloudwatch log group's name
END RequestId: cf8065ed-ff19-4e66-ae54-195d9c6b976b
REPORT RequestId: cf8065ed-ff19-4e66-ae54-195d9c6b976b  Init Duration: 0.71 ms  Duration: 343.71 ms     Billed Duration: 344 ms Memory Size: 256 MB     Max Memory Used: 256 MB 
huh,, i have no idea! # outpustream result