

# Implement code before or after Lambda function snapshots
<a name="snapstart-runtime-hooks"></a>

You can use runtime hooks to implement code before Lambda creates a snapshot or after Lambda resumes a function from a snapshot. Runtime hooks are useful for a variety of purposes, such as:
+ **Cleanup and initialization:** Before a snapshot is created, you can use a runtime hook to perform cleanup or resource release operations. After a snapshot is restored, you can use a runtime hook to re-initialize any resources or state that were not captured in the snapshot.
+ **Dynamic configuration:** You can use runtime hooks to dynamically update configuration or other metadata before a snapshot is created or after it is restored. This can be useful if your function needs to adapt to changes in the runtime environment.
+ **External integrations:** You can use runtime hooks to integrate with external services or systems, such as sending notifications or updating external state, as part of the checkpointing and restoration process.
+ **Performance tuning:** You can use runtime hooks to fine-tune your function's startup sequence, such as by preloading dependencies. For more information, see [Performance tuning](snapstart-best-practices.md#snapstart-tuning).

The following pages explain how to implement runtime hooks for your preferred runtime.

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

# Lambda SnapStart runtime hooks for Java
<a name="snapstart-runtime-hooks-java"></a>

You can use runtime hooks to implement code before Lambda creates a snapshot or after Lambda resumes a function from a snapshot. Runtime hooks are available as part of the open-source Coordinated Restore at Checkpoint (CRaC) project. CRaC is in development for the [Open Java Development Kit (OpenJDK)](https://wiki.openjdk.org/display/crac). For an example of how to use CRaC with a reference application, see the [CRaC](https://github.com/CRaC/docs/blob/master/STEP-BY-STEP.md) repository on GitHub. CRaC uses three main elements:
+ `Resource` – An interface with two methods, `beforeCheckpoint()` and `afterRestore()`. Use these methods to implement the code that you want to run before a snapshot and after a restore.
+ `Context <R extends Resource>` – To receive notifications for checkpoints and restores, a `Resource` must be registered with a `Context`.
+ `Core` – The coordination service, which provides the default global `Context` via the static method `Core.getGlobalContext()`.

For more information about `Context` and `Resource`, see [Package org.crac](https://javadoc.io/doc/io.github.crac/org-crac/latest/index.html) in the CRaC documentation.

Use the following steps to implement runtime hooks with the [org.crac package](https://github.com/CRaC/org.crac). The Lambda runtime contains a customized CRaC context implementation that calls your runtime hooks before checkpointing and after restoring.

## Runtime hook registration and execution
<a name="runtime-hooks-registration-java"></a>

The order that Lambda executes your runtime hooks is determined by the order of registration. Registration order follows the order of import, definition, or execution in your code.
+ `beforeCheckpoint()`: Executed in the reverse order of registration
+ `afterRestore()`: Executed in the order of registration

Make sure that all registered hooks are properly imported and included in your function's code. If you register runtime hooks in a separate file or module, you must ensure that the module is imported, either directly or as part of a larger package, in your function's handler file. If the file or module is not imported in the function handler, Lambda ignores the runtime hooks.

**Note**  
When Lambda creates a snapshot, your initialization code can run for up to 15 minutes. The time limit is 130 seconds or the [configured function timeout](configuration-timeout.md) (maximum 900 seconds), whichever is higher. Your `beforeCheckpoint()` runtime hooks count towards the initialization code time limit. When Lambda restores a snapshot, the runtime must load and `afterRestore()` runtime hooks must complete within the timeout limit (10 seconds). Otherwise, you'll get a SnapStartTimeoutException.

## Step 1: Update the build configuration
<a name="runtime-hooks-java-update-build"></a>

Add the `org.crac` dependency to the build configuration. The following example uses Gradle. For examples for other build systems, see the [Apache Maven documentation](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'
}
```

## Step 2: Update the Lambda handler
<a name="runtime-hooks-java-update-handler"></a>

The Lambda function *handler* is the method in your function code that processes events. When your function is invoked, Lambda runs the handler method. Your function runs until the handler returns a response, exits, or times out.

For more information, see [Define Lambda function handler in Java](java-handler.md).

The following example handler shows how to run code before checkpointing (`beforeCheckpoint()`) and after restoring (`afterRestore()`). This handler also registers the `Resource` to the runtime-managed global `Context`.

**Note**  
When Lambda creates a snapshot, your initialization code can run for up to 15 minutes. The time limit is 130 seconds or the [configured function timeout](configuration-timeout.md) (maximum 900 seconds), whichever is higher. Your `beforeCheckpoint()` runtime hooks count towards the initialization code time limit. When Lambda restores a snapshot, the runtime (JVM) must load and `afterRestore()` runtime hooks must complete within the timeout limit (10 seconds). Otherwise, you'll get a 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` maintains only a [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) to the registered object. If a [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) is garbage collected, runtime hooks do not run. Your code must maintain a strong reference to the `Resource` to guarantee that the runtime hook runs.

Here are two examples of patterns to avoid:

**Example – Object without a strong reference**  

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

**Example – Objects of anonymous classes**  

```
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 {
    // ...
   }

} );
```

Instead, maintain a strong reference. In the following example, the registered resource isn't garbage collected and runtime hooks run consistently.

**Example – Object with a strong reference**  

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

# Lambda SnapStart runtime hooks for Python
<a name="snapstart-runtime-hooks-python"></a>

You can use runtime hooks to implement code before Lambda creates a snapshot or after Lambda resumes a function from a snapshot. Python runtime hooks are available as part of the open-source [Snapshot Restore for Python library](https://pypi.org/project/snapshot-restore-py/), which is included in Python managed runtimes. This library provides two decorators that you can use to define your runtime hooks:
+ `@register_before_snapshot`: For functions you want to run before Lambda creates a snapshot.
+ `@register_after_restore`: For functions you want to run when Lambda resumes a function from a snapshot.

Alternatively, you can use the following methods to register callables for runtime hooks:
+ `register_before_snapshot(func, *args, **kwargs)`
+ `register_after_restore(func, *args, **kwargs)`

## Runtime hook registration and execution
<a name="runtime-hooks-registration-python"></a>

The order that Lambda executes your runtime hooks is determined by the order of registration:
+ Before snapshot: Executed in the reverse order of registration
+ After snapshot: Executed in the order of registration

The order of runtime hook registration depends on how you define the hooks. When using decorators (`@register_before_snapshot` and `@register_after_restore`), the registration order follows the order of import, definition, or execution in your code. If you need more control over the registration order, use the `register_before_snapshot()` and `register_after_restore()` methods instead of decorators.

Make sure that all registered hooks are properly imported and included in your function's code. If you register runtime hooks in a separate file or module, you must ensure that the module is imported, either directly or as part of a larger package, in your function's handler file. If the file or module is not imported in the function handler, Lambda ignores the runtime hooks.

**Note**  
When Lambda creates a snapshot, your initialization code can run for up to 15 minutes. The time limit is 130 seconds or the [configured function timeout](configuration-timeout.md) (maximum 900 seconds), whichever is higher. Your `@register_before_snapshot` runtime hooks count towards the initialization code time limit. When Lambda restores a snapshot, the runtime must load and `@register_after_restore` runtime hooks must complete within the timeout limit (10 seconds). Otherwise, you'll get a SnapStartTimeoutException.

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

The following example handler shows how to run code before checkpointing (`@register_before_snapshot`) and after restoring (`@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
```

For more examples, see [Snapshot Restore for Python](https://github.com/aws/snapshot-restore-py/tree/main/examples) in the AWS GitHub repository.

# Lambda SnapStart runtime hooks for .NET
<a name="snapstart-runtime-hooks-dotnet"></a>

You can use runtime hooks to implement code before Lambda creates a snapshot or after Lambda resumes a function from a snapshot. .NET runtime hooks are available as part of the [Amazon.Lambda.Core](https://www.nuget.org/packages/Amazon.Lambda.Core) package (version 2.5.0 or later). This library provides two methods that you can use to define your runtime hooks:
+ `RegisterBeforeSnapshot()`: Code to run before snapshot creation
+ `RegisterAfterSnapshot()`: Code to run after resuming a function from a snapshot

**Note**  
If you're using the [Lambda Annotations framework for .NET](csharp-handler.md#csharp-handler-annotations), upgrade to [Amazon.Lambda.Annotations](https://www.nuget.org/packages/Amazon.Lambda.Annotations) version 1.6.0 or later to ensure compatibility with SnapStart.

## Runtime hook registration and execution
<a name="runtime-hooks-registration-dotnet"></a>

Register your hooks in your initialization code. Consider the following guidelines based on your Lambda function's [execution model](csharp-handler.md#csharp-handler-setup):
+ For the [executable assembly approach](csharp-handler.md#csharp-executable-assembly-handlers), register your hooks before you start the Lambda bootstrap with `RunAsync`.
+ For the [class library approach](csharp-handler.md#csharp-class-library-handlers), register your hooks in the handler class constructor.
+ For [ASP.NET Core applications](csharp-package-asp.md), register your hooks before calling the `WebApplications.Run` method.

To register runtime hooks for SnapStart in .NET, use the following methods:

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

When multiple hook types are registered, the order that Lambda executes your runtime hooks is determined by the order of registration:
+ `RegisterBeforeSnapshot()`: Executed in the reverse order of registration
+ `RegisterAfterSnapshot()`: Executed in the order of registration

**Note**  
When Lambda creates a snapshot, your initialization code can run for up to 15 minutes. The time limit is 130 seconds or the [configured function timeout](configuration-timeout.md) (maximum 900 seconds), whichever is higher. Your `RegisterBeforeSnapshot()` runtime hooks count towards the initialization code time limit. When Lambda restores a snapshot, the runtime must load and `RegisterAfterSnapshot()` runtime hooks must complete within the timeout limit (10 seconds). Otherwise, you'll get a SnapStartTimeoutException.

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

The following example function shows how to run code before checkpointing (`RegisterBeforeSnapshot`) and after restoring (`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
        };
    }
}
```