

# Lambda 함수 스냅샷 전후 코드 구현
<a name="snapstart-runtime-hooks"></a>

Lambda가 스냅샷을 생성하기 전이나 Lambda가 스냅샷에서 함수를 재개한 후에 런타임 후크를 사용하여 코드를 구현할 수 있습니다. 런타임 후크는 다음과 같은 다양한 목적으로 유용합니다.
+ **정리 및 초기화:** 스냅샷을 생성하기 전에 런타임 후크를 사용하여 정리 또는 리소스 해제 작업을 수행할 수 있습니다. 스냅샷이 복원된 후 런타임 후크를 사용하여 스냅샷에 캡처되지 않은 리소스 또는 상태를 다시 초기화할 수 있습니다.
+ **동적 구성:** 스냅샷을 생성하기 전 또는 복원한 후에 런타임 후크를 사용하여 구성 또는 기타 메타데이터를 동적으로 업데이트할 수 있습니다. 함수가 런타임 환경의 변경 사항에 맞게 적응해야 하는 경우에 유용할 수 있습니다.
+ **외부 통합:** 런타임 후크를 사용하여 체크포인트 및 복원 프로세스의 일부로 알림 전송 또는 외부 상태 업데이트와 같은 외부 서비스 또는 시스템과 통합할 수 있습니다.
+ **성능 조정:** 런타임 후크를 사용하여 종속 항목을 미리 로드하는 등 함수의 시작 시퀀스를 미세 조정할 수 있습니다. 자세한 내용은 [성능 튜닝](snapstart-best-practices.md#snapstart-tuning) 단원을 참조하십시오.

다음 페이지에서는 원하는 런타임에 대해 런타임 후크를 구현하는 방법을 설명합니다.

**Topics**
+ [Java](snapstart-runtime-hooks-java.md)
+ [Python](snapstart-runtime-hooks-python.md)
+ [.NET](snapstart-runtime-hooks-dotnet.md)

# Java에 대한 Lambda SnapStart 런타임 후크
<a name="snapstart-runtime-hooks-java"></a>

Lambda가 스냅샷을 생성하기 전이나 Lambda가 스냅샷에서 함수를 재개한 후에 런타임 후크를 사용하여 코드를 구현할 수 있습니다. 런타임 후크는 오픈 소스 체크포인트 Coordinated Restore at Checkpoint(CRaC) 프로젝트의 일부로 제공됩니다. [Open Java Development Kit(OpenJDK)](https://wiki.openjdk.org/display/crac)용 CRaC는 개발 중입니다. 참조 애플리케이션에 CRaC를 사용하는 방법의 예는 GitHub에서 [CRaC](https://github.com/CRaC/docs/blob/master/STEP-BY-STEP.md) 리포지토리를 참조하세요. CRaC는 세 가지 주요 요소를 사용합니다.
+ `Resource` - `beforeCheckpoint()`와 `afterRestore()`라는 두 가지 메서드가 있는 인터페이스입니다. 이러한 메서드를 사용하여 스냅샷 생성 전과 복원 후에 실행할 코드를 구현합니다.
+ `Context <R extends Resource>` - 체크포인트 및 복원에 대한 알림을 받으려면 `Resource`를 `Context`에 등록해야 합니다.
+ `Core` - 정적 메서드 `Core.getGlobalContext()`를 통해 기본 글로벌 `Context`를 제공하는 조정 서비스입니다.

`Context` 및 `Resource`에 대한 자세한 내용은 CRaC 설명서에서 [org.crac 패키징](https://javadoc.io/doc/io.github.crac/org-crac/latest/index.html)을 참조하세요.

다음 단계에 따라 [org.crac 패키지](https://github.com/CRaC/org.crac)를 사용하여 런타임 후크를 구현합니다. Lambda 런타임에는 체크포인트를 생성하기 전과 복원 후에 런타임 후크를 호출하는 사용자 지정 CRaC 컨텍스트 구현이 포함되어 있습니다.

## 런타임 후크 등록 및 실행
<a name="runtime-hooks-registration-java"></a>

Lambda에서 런타임 후크를 실행하는 순서는 등록 순서에 따라 결정됩니다. 등록 순서는 코드의 가져오기, 정의 또는 실행 순서를 따릅니다.
+ `beforeCheckpoint()`: 등록의 역순으로 실행됨
+ `afterRestore()`: 등록 순서대로 실행됨

등록된 모든 후크를 올바르게 가져와서 함수 코드에 포함했는지 확인합니다. 별도의 파일 또는 모듈에 런타임 후크를 등록하는 경우 모듈을 함수의 핸들러 파일에 직접 가져오거나 더 큰 패키지의 일부로 가져와야 합니다. 함수 핸들러에 파일 또는 모듈을 가져오지 않으면 Lambda는 런타임 후크를 무시합니다.

**참고**  
Lambda가 스냅샷을 생성할 때 초기화 코드를 최대 15분 동안 실행할 수 있습니다. 시간 제한은 130초 또는 [구성된 함수 제한 시간](configuration-timeout.md)(최대 900초) 중 더 높은 값입니다. `beforeCheckpoint()` 런타임 후크는 초기화 코드 시간 제한에 포함됩니다. Lambda에서 스냅샷을 복원하는 경우 런타임이 로드되고 `afterRestore()` 런타임 후크가 제한 시간(10초) 내에 완료되어야 합니다. 그렇지 않으면 SnapStartTimeoutException이 발생합니다.

## 1단계: 빌드 구성 업데이트
<a name="runtime-hooks-java-update-build"></a>

빌드 구성에 `org.crac` 종속성을 추가합니다. 다음 예에서는 Gradle을 사용합니다. 다른 빌드 시스템의 예제는 [Apache Maven 설명서](https://search.maven.org/artifact/io.github.crac/org-crac/0.1.3/jar)를 참조하세요.

```
dependencies {
    compile group: 'com.amazonaws', name: 'aws-lambda-java-core', version: '1.2.1'
    # All other project dependecies go here:
    # ...
    # Then, add the org.crac dependency:
 implementation group: 'org.crac', name: 'crac', version: '1.4.0'
}
```

## 2단계: Lambda 핸들러 업데이트
<a name="runtime-hooks-java-update-handler"></a>

Lambda 함수의 *핸들러*는 이벤트를 처리하는 함수 코드의 메서드입니다. 함수가 간접 호출되면 Lambda는 핸들러 메서드를 실행합니다. 함수는 핸들러가 응답을 반환하거나 종료하거나 제한 시간이 초과될 때까지 실행됩니다.

자세한 내용은 [Java에서 Lambda 함수 핸들러 정의](java-handler.md) 섹션을 참조하세요.

다음 예제 핸들러는 체크포인트 생성 전(`beforeCheckpoint()`)과 복원 후(`afterRestore()`)에 코드를 실행하는 방법을 보여줍니다. 또한 이 핸들러는 런타임 관리 글로벌 `Resource`에 `Context`를 등록합니다.

**참고**  
Lambda가 스냅샷을 생성할 때 초기화 코드를 최대 15분 동안 실행할 수 있습니다. 시간 제한은 130초 또는 [구성된 함수 제한 시간](configuration-timeout.md)(최대 900초) 중 더 높은 값입니다. `beforeCheckpoint()` 런타임 후크는 초기화 코드 시간 제한에 포함됩니다. Lambda가 스냅샷을 복원할 때, 런타임(JVM)이 로드되고 `afterRestore()` 런타임 후크가 제한 시간(10초) 내에 완료되어야 합니다. 그렇지 않으면 SnapStartTimeoutException이 발생합니다.

```
...
  import org.crac.Resource;
  import org.crac.Core;
  ... 
public class CRaCDemo implements RequestStreamHandler, Resource {
    public CRaCDemo() {
      Core.getGlobalContext().register(this);
    }
    public String handleRequest(String name, Context context) throws IOException {
      System.out.println("Handler execution");
      return "Hello " + name;
    }
    @Override
    public void beforeCheckpoint(org.crac.Context<? extends Resource> context)
        throws Exception {
      System.out.println("Before checkpoint");
    }
    @Override
    public void afterRestore(org.crac.Context<? extends Resource> context)
        throws Exception {
      System.out.println("After restore");
```

`Context`는 등록된 객체에 대해서만 [https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ref/WeakReference.html](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ref/WeakReference.html)를 유지합니다. [https://javadoc.io/static/io.github.crac/org-crac/0.1.3/org/crac/Resource.html](https://javadoc.io/static/io.github.crac/org-crac/0.1.3/org/crac/Resource.html)가 가비지 수집된 경우 런타임 후크가 실행되지 않습니다. 런타임 후크가 실행되도록 하려면 코드에서 `Resource`에 대한 강력한 참조를 유지해야 합니다.

다음은 피해야 할 두 가지 패턴의 예입니다.

**Example - 강력한 참조가 없는 객체**  

```
Core.getGlobalContext().register( new MyResource() );
```

**Example - 익명 클래스의 객체**  

```
Core.getGlobalContext().register( new Resource() {
   
   @Override
   public void afterRestore(Context<? extends Resource> context) throws Exception {
    // ...
   }
   
   @Override
   public void beforeCheckpoint(Context<? extends Resource> context) throws Exception {
    // ...
   }

} );
```

대신 강력한 참조를 유지하세요. 다음 예제에서 등록된 리소스는 가비지 수집되지 않았으며 런타임 후크가 일관되게 실행됩니다.

**Example - 강력한 참조가 있는 객체**  

```
Resource myResource = new MyResource(); // This reference must be maintained to prevent the registered resource from being garbage collected
Core.getGlobalContext().register( myResource );
```

# Python에 대한 Lambda SnapStart 런타임 후크
<a name="snapstart-runtime-hooks-python"></a>

Lambda가 스냅샷을 생성하기 전이나 Lambda가 스냅샷에서 함수를 재개한 후에 런타임 후크를 사용하여 코드를 구현할 수 있습니다. Python 런타임 후크는 Python 관리형 런타임에 포함된 오픈 소스 [Snapshot Restore for Python 라이브러리](https://pypi.org/project/snapshot-restore-py/)의 일부로 사용할 수 있습니다. 이 라이브러리에서는 런타임 후크를 정의하는 데 사용할 수 있는 두 가지 데코레이터를 제공합니다.
+ `@register_before_snapshot`: Lambda가 스냅샷을 생성하기 전에 실행할 함수의 경우.
+ `@register_after_restore`: Lambda가 스냅샷에서 함수를 재개하는 경우 실행할 함수의 경우.

또는 다음 방법을 사용하여 런타임 후크에 대한 직접 호출 가능 항목을 등록할 수 있습니다.
+ `register_before_snapshot(func, *args, **kwargs)`
+ `register_after_restore(func, *args, **kwargs)`

## 런타임 후크 등록 및 실행
<a name="runtime-hooks-registration-python"></a>

Lambda에서 런타임 후크를 실행하는 순서는 등록 순서에 따라 결정됩니다.
+ 스냅샷 이전: 등록의 역순으로 실행됨
+ 스냅샷 이후: 등록 순서대로 실행됨

런타임 후크 등록 순서는 후크를 정의하는 방법에 따라 달라집니다. 데코레이터(`@register_before_snapshot` 및 `@register_after_restore`)를 사용하는 경우 등록 순서는 코드의 가져오기, 정의 또는 실행 순서를 따릅니다. 등록 순서를 더 제어해야 하는 경우 데코레이터 대신 `register_before_snapshot()` 및 `register_after_restore()` 메서드를 사용합니다.

등록된 모든 후크를 올바르게 가져와서 함수 코드에 포함했는지 확인합니다. 별도의 파일 또는 모듈에 런타임 후크를 등록하는 경우 모듈을 함수의 핸들러 파일에 직접 가져오거나 더 큰 패키지의 일부로 가져와야 합니다. 함수 핸들러에 파일 또는 모듈을 가져오지 않으면 Lambda는 런타임 후크를 무시합니다.

**참고**  
Lambda가 스냅샷을 생성할 때 초기화 코드를 최대 15분 동안 실행할 수 있습니다. 시간 제한은 130초 또는 [구성된 함수 제한 시간](configuration-timeout.md)(최대 900초) 중 더 높은 값입니다. `@register_before_snapshot` 런타임 후크는 초기화 코드 시간 제한에 포함됩니다. Lambda에서 스냅샷을 복원하는 경우 런타임이 로드되고 `@register_after_restore` 런타임 후크가 제한 시간(10초) 내에 완료되어야 합니다. 그렇지 않으면 SnapStartTimeoutException이 발생합니다.

## 예제
<a name="runtime-hooks-python-code-sample"></a>

다음 예제 핸들러는 체크포인트 생성 전(`@register_before_snapshot`)과 복원 후(`@register_after_restore`)에 코드를 실행하는 방법을 보여줍니다.

```
from snapshot_restore_py import register_before_snapshot, register_after_restore

def lambda_handler(event, context):
    # Handler code

@register_before_snapshot
def before_checkpoint():
    # Logic to be executed before taking snapshots

@register_after_restore
def after_restore():
    # Logic to be executed after restore
```

추가 예제는 AWS GitHub 리포지토리의 [Snapshot Restore for Python](https://github.com/aws/snapshot-restore-py/tree/main/examples)을 참조하세요.

# .NET에 대한 Lambda SnapStart 런타임 후크
<a name="snapstart-runtime-hooks-dotnet"></a>

Lambda가 스냅샷을 생성하기 전이나 Lambda가 스냅샷에서 함수를 재개한 후에 런타임 후크를 사용하여 코드를 구현할 수 있습니다. .NET 런타임 후크는 [Amazon.Lambda.Core](https://www.nuget.org/packages/Amazon.Lambda.Core) 패키지(버전 2.5.0 이상)의 일부로 사용 가능합니다. 이 라이브러리에서는 런타임 후크를 정의하는 데 사용할 수 있는 두 가지 방법을 제공합니다.
+ `RegisterBeforeSnapshot()`: 스냅샷 생성 전에 실행할 코드
+ `RegisterAfterSnapshot()`: 스냅샷에서 함수를 재개한 후 실행할 코드

**참고**  
[.NET에 대한 Lambda 주석 프레임워크](csharp-handler.md#csharp-handler-annotations)를 사용하는 경우 SnapStart와의 호환성을 보장하기 위해 [Amazon.Lambda.Annotations](https://www.nuget.org/packages/Amazon.Lambda.Annotations) 버전 1.6.0 이상으로 업그레이드합니다.

## 런타임 후크 등록 및 실행
<a name="runtime-hooks-registration-dotnet"></a>

초기화 코드에 후크를 등록합니다. Lambda 함수의 [실행 모델](csharp-handler.md#csharp-handler-setup)에 따라 다음 지침을 고려합니다.
+ [실행 가능한 어셈블리 접근 방식](csharp-handler.md#csharp-executable-assembly-handlers)의 경우 `RunAsync`로 Lambda 부트스트랩을 시작하기 전에 후크를 등록합니다.
+ [클래스 라이브러리 접근 방식](csharp-handler.md#csharp-class-library-handlers)의 경우 핸들러 클래스 생성자에 후크를 등록합니다.
+ [ASP.NET Core 애플리케이션](csharp-package-asp.md)의 경우 `WebApplications.Run` 메서드를 직접 호출하기 전에 후크를 등록합니다.

.NET에서 SnapStart에 대한 런타임 후크를 등록하려면 다음 방법을 사용합니다.

```
Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot(BeforeCheckpoint);
Amazon.Lambda.Core.SnapshotRestore.RegisterAfterRestore(AfterCheckpoint);
```

여러 후크 유형이 등록되면 Lambda에서 런타임 후크를 실행하는 순서는 등록 순서에 따라 결정됩니다.
+ `RegisterBeforeSnapshot()`: 등록의 역순으로 실행됨
+ `RegisterAfterSnapshot()`: 등록 순서대로 실행됨

**참고**  
Lambda가 스냅샷을 생성할 때 초기화 코드를 최대 15분 동안 실행할 수 있습니다. 시간 제한은 130초 또는 [구성된 함수 제한 시간](configuration-timeout.md)(최대 900초) 중 더 높은 값입니다. `RegisterBeforeSnapshot()` 런타임 후크는 초기화 코드 시간 제한에 포함됩니다. Lambda에서 스냅샷을 복원하는 경우 런타임이 로드되고 `RegisterAfterSnapshot()` 런타임 후크가 제한 시간(10초) 내에 완료되어야 합니다. 그렇지 않으면 SnapStartTimeoutException이 발생합니다.

## 예제
<a name="runtime-hooks-dotnet-code-sample"></a>

다음 함수 예제에서는 체크포인트 생성 전(`RegisterBeforeSnapshot`)과 복원 후(`RegisterAfterRestore`)에 코드를 실행하는 방법을 보여줍니다.

```
public class SampleClass
{
    public SampleClass()
    {
        Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot(BeforeCheckpoint);
        Amazon.Lambda.Core.SnapshotRestore.RegisterAfterRestore(AfterCheckpoint);
    }

    private ValueTask BeforeCheckpoint()
    {
        // Add logic to be executed before taking the snapshot
        return ValueTask.CompletedTask;
    }

    private ValueTask AfterCheckpoint()
    {
        // Add logic to be executed after restoring the snapshot
        return ValueTask.CompletedTask;
    }

    public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        // Add business logic

        return new APIGatewayProxyResponse
        {
            StatusCode = 200
        };
    }
}
```