AWS Lambda
개발자 가이드

AWS Lambda 함수 핸들러(C#)

Lambda 함수를 생성하는 시점에 서비스가 사용자를 대신하여 함수를 실행할 때 AWS Lambda가 호출할 수 있는 핸들러를 지정합니다.

클래스에서 Lambda 함수 핸들러를 인스턴스나 정적 메서드로 정의합니다. 원할 경우, 현재 실행에 대한 정보(예: 현재 함수의 이름, 메모리 한도, 남아 있는 실행 시간, 로깅 등)를 액세스하는 데 사용할 수 있는 인터페이스인 ILambdaContext 유형의 메서드 파라미터를 정의하여 Lambda 콘텍스트 객체에 액세스할 수 있습니다.

returnType handler-name(inputType input, ILambdaContext context) { ... }

구문에서 다음 사항에 유의하십시오.

  • inputType – 첫 번째 핸들러 파라미터는 핸들러에 대한 입력으로, 이벤트 데이터(이벤트 소스에서 게시) 또는 문자열이나 사용자 지정 데이터 객체 같은 사용자 지정 입력이 될 수 있습니다.

  • returnType – Lambda 함수를 동기식으로 호출할 계획인 경우(RequestResponse 호출 유형 사용), 지원되는 데이터 유형 중 하나를 사용하여 함수의 출력을 반환할 수 있습니다. 예를 들어 함수를 모바일 애플리케이션 백엔드로 사용하는 경우에는 이를 동기식으로 호출합니다. 출력 데이터 유형이 JSON으로 직렬화됩니다.

    Lambda 함수를 비동기식으로 호출할 계획인 경우(Event 호출 유형 사용), returnTypevoid여야 합니다. 예를 들어 Amazon S3나 Amazon SNS 같은 이벤트 소스에서 AWS Lambda를 사용할 경우, 이러한 이벤트 소스는 Event 호출 유형을 사용하여 Lambda 함수를 호출합니다.

스트림 처리

기본적으로 System.IO.Stream 유형만 입력 파라미터로 지원됩니다.

예를 들어 다음과 같은 C# 코드 예제를 고려해 보십시오.

using System.IO; namespace Example { public class Hello { public Stream MyHandler(Stream stream) { //function logic } }

C# 코드 예제에서 첫 번째 핸들러 파라미터는 핸들러에 대한 입력(MyHandler)인데, 이벤트 데이터(Amazon S3 같이 이벤트 소스에서 게시)나 Stream(예제 참조) 또는 사용자 지정 데이터 객체와 같이 사용자가 제공한 사용자 지정 입력이 될 수 있습니다. 출력은 Stream 유형입니다.

표준 데이터 유형 처리

아래에 나와 있듯이 기타 모든 유형에서는 직렬 변환기를 지정해야 합니다.

  • 기본 .NET 유형(문자열 또는 int).

  • 모음 및 맵 - IList, IEnumerable, IList<T>, Array, IDictionary, IDictionary<TKey, TValue>

  • POCO 유형(POCO)

  • 사전 정의된 AWS 이벤트 유형

  • 비동기식 호출의 경우, Lambda가 반환 유형을 무시합니다. 이러한 경우에 반환 유형은 무효로 설정될 수 있습니다.

  • .NET 비동기식 프로그래밍을 사용하고 있는 경우에는 반환 유형이 Task and Task<T> 유형이고 asyncawait 키워드를 사용할 수 있습니다. 자세한 내용은 AWS Lambda에서 C# 함수로 작성된 비동기식 핸들러 사용 단원을 참조하십시오.

함수 입력 및 출력 파라미터가 System.IO.Stream 유형이 아닌 경우에는 이를 직렬화해야 합니다. AWS Lambda가 애플리케이션의 어셈블리 또는 메서드 수준에서 적용이 가능한 기본 직렬 변환기를 제공하거나, 사용자가 Amazon.Lambda.Core 라이브러리에서 제공되는 ILambdaSerializer 인터페이스를 구현하여 자체적으로 정의할 수 있습니다. 자세한 내용은 AWS Lambda 배포 패키지(C#) 단원을 참조하십시오.

메서드에 기본 직렬 변환기 속성을 추가하려면 먼저 project.json 파일에서 Amazon.Lambda.Serialization.Json에 대한 종속 프로그램을 추가합니다.

{ "version": "1.0.0-*", "dependencies":{ "Microsoft.NETCore.App": { "type": "platform", "version": "1.0.1" }, "Amazon.Lambda.Serialization.Json": "1.3.0" }, "frameworks": { "netcoreapp1.0": { "imports": "dnxcore50" } } }

아래 예제는 하나의 메서드와 또 다른 메서드에서 기본 Json.NET 직렬 변환기를 지정함으로써 유연성을 높일 수 있음을 보여줍니다.

public class ProductService{ [LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] public Product DescribeProduct(DescribeProductRequest request) { return catalogService.DescribeProduct(request.Id); } [LambdaSerializer(typeof(MyJsonSerializer))] public Customer DescribeCustomer(DescribeCustomerRequest request) { return customerService.DescribeCustomer(request.Id); } }

핸들러 서명

Lambda 함수를 생성할 때 핸들러 문자열을 제공하여 호출하려는 코드를 어디에서 찾을지 AWS Lambda에게 알려줘야 합니다. C#에서 형식은 다음과 같습니다.

ASSEMBLY::TYPE::METHOD 위치:

  • ASSEMBLY는 애플리케이션에 대한 .NET 어셈블리 파일의 이름입니다. .NET Core CLI를 사용하여 애플리케이션을 빌드할 때 project.json에서 buildOptions.outputName 설정을 사용하여 어셈블리 이름을 설정하지 않은 경우에는 ASSEMBLY 이름이 project.json 파일을 포함하는 폴더의 이름이 됩니다. 자세한 내용은 .NET Core CLI 단원을 참조하십시오. 이 예제의 경우, 폴더 이름이 HelloWorldApp라고 가정해 봅시다.

  • TYPE는 핸들러 유형의 전체 이름으로, NamespaceClassName으로 이루어져 있습니다. 이 예제의 경우 Example.Hello입니다.

  • METHOD는 함수 핸들러의 이름으로, 이 예제의 경우 MyHandler입니다.

궁극적으로 서명은 Assembly::Namespace.ClassName::MethodName라는 형식을 갖게 됩니다.

다시 한번 다음 예제를 고려해보십시오.

using System.IO; namespace Example { public class Hello { public Stream MyHandler(Stream stream) { //function logic } }

핸들러 문자열은 HelloWorldApp::Example.Hello::MyHandler가 됩니다.

중요

핸들러 문자열에 지정된 메서드가 오버로드된 경우에는 Lambda가 호출해야 하는 메서드의 정확한 서명을 제공해야 합니다. 그렇지 않으면 확인 시 여러 개의 서명 중에서 선택을 해야 하는 경우(오버로드), AWS Lambda가 유효한 서명을 거부하게 됩니다.

Lambda 함수 직렬화

Stream 객체 이외의 입력 또는 출력 유형을 사용하는 Lambda 함수의 경우, 애플리케이션에 직렬화 라이브러리를 추가해야 합니다. 다음과 같은 방법으로 추가가 가능합니다.

  • Amazon.Lambda.Serialization.Json NuGet 패키지를 사용합니다. 이 라이브러리에서는 JSON.NET을 사용해 직렬화를 처리합니다.

  • Amazon.Lambda.Core 라이브러리의 일부로 사용할 수 있는 ILambdaSerializer 인터페이스를 구현하여 자체 직렬화 라이브러리를 생성합니다. 인터페이스는 두 가지 메서드를 정의합니다.

    • T Deserialize<T>(Stream requestStream);

      이 메서드를 구현하여 Invoke API에서 Lambda 함수 핸들러로 전달되는 객체로 요청 페이로드를 역직렬화합니다.

    • T Serialize<T>(T response, Stream responseStream);.

      이 메서드를 구현하여 Lambda 함수 핸들러에서 반환된 결과를 Invoke API에서 반환된 응답 페이로드로 직렬화합니다.

이를 종속 프로그램으로 MyProject.csproj 파일에 추가하여 원하는 serializer는 무엇이든 사용할 수 있습니다.

... <ItemGroup> <PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" /> <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.3.0" /> </ItemGroup>

그런 다음, AssemblyInfo.cs 파일에 이를 추가합니다. 예를 들어 기본 Json.NET serializer를 사용하고 있는 경우에는 이를 추가했을 것입니다.

[assembly:LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

참고

어셈블리 수준에서 지정된 기본 serializer를 재정의하도록 메서드 수준에서 사용자 지정 직렬화 속성을 정의할 수 있습니다. 자세한 내용은 표준 데이터 유형 처리 단원을 참조하십시오.

Lambda 함수 핸들러 제한 사항

핸들러 서명에는 몇 가지 제한이 있습니다.

  • unsafe이어서는 안 되고, 핸들러 메서드 및 종속 프로그램 내에서 unsafe 콘텍스트가 사용될 수는 있지만 핸들러 서명에서 포인터 유형을 사용해서는 안 됩니다. 자세한 내용은 unsafe(C# Reference)를 참조하십시오.

  • params 키워드를 사용하여 다수의 파라미터를 전달하거나 ArgIterator를 입력으로 사용하거나 다수의 파라미터를 지원하는 데 사용되는 파라미터를 반환하지 않을 수 있습니다.

  • 핸들러는 일반 메서드(예: IList<T> Sort<T>(IList<T> input))가 아닙니다.

  • 서명 async void이 있는 비동기식 핸들러는 지원되지 않습니다.

AWS Lambda에서 C# 함수로 작성된 비동기식 핸들러 사용

Lambda 함수에 대용량 파일을 Amazon S3에 업로드하거나 대규모 레코드 스트림을 DynamoDB에서 읽어오는 등의 장기 실행 프로세스가 필요하다고 판단되는 경우에는 async/await 패턴을 활용할 수 있습니다. 이 서명을 사용하면 Lambda는 함수를 동기식으로 실행하고 그 함수가 응답을 반환할 때까지 또는 실행이 시간 초과될 때까지 기다립니다.

public async Task<Response> ProcessS3ImageResizeAsync(SimpleS3Event input) { var response = await client.DoAsyncWork(input); return response; }

이 패턴을 사용하는 경우에는 몇 가지 고려해야 할 사항이 있습니다.

  • AWS Lambda는 async void 메서드를 지원하지 않습니다.

  • await 연산자를 구현하지 않고 비동기식 Lambda 함수를 생성한 경우, .NET은 컴파일러 경고를 발행하고 사용자는 예상하지 않은 동작을 관찰하게 됩니다. 예를 들어, 일부 비동기 작업은 다른 작업이 실행되지 않을 때 실행됩니다. 또는 일부 비동기 작업은 함수 실행이 완료되어야 완료됩니다.

    public async Task ProcessS3ImageResizeAsync(SimpleS3Event event) // Compiler warning { client.DoAsyncWork(input); }
  • Lambda 함수에는 동시 호출이 가능한 비동기식 호출이 여러 개 포함될 수 있습니다. Task.WhenAllTask.WhenAny 메서드를 사용하여 여러 작업을 수행할 수 있습니다. Task.WhenAll 메서드를 사용하려면 작업 목록을 메서드에 배열로 전달해야 합니다. 아래 예제와 같이 배열에 어떤 작업도 포함시키지 않으면 작업이 완료되기 전에 해당 호출이 반환될 수 있습니다.

    public async Task DoesNotWaitForAllTasks1() { // In Lambda, Console.WriteLine goes to CloudWatch Logs. var task1 = Task.Run(() => Console.WriteLine("Test1")); var task2 = Task.Run(() => Console.WriteLine("Test2")); var task3 = Task.Run(() => Console.WriteLine("Test3")); // Lambda may return before printing "Test2" since we never wait on task2. await Task.WhenAll(task1, task3); }

    Task.WhenAny 메서드를 사용하려면 다시 한 번 작업 목록을 메서드에 배열로 전달해야 합니다. 다른 작업들은 여전히 실행 중이더라도 첫 번째 작업이 완료되는 즉시 호출이 반환됩니다.

    public async Task DoesNotWaitForAllTasks2() { // In Lambda, Console.WriteLine goes to CloudWatch Logs. var task1 = Task.Run(() => Console.WriteLine("Test1")); var task2 = Task.Run(() => Console.WriteLine("Test2")); var task3 = Task.Run(() => Console.WriteLine("Test3")); // Lambda may return before printing all tests since we're only waiting for one to finish. await Task.WhenAny(task1, task2, task3); }