

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Lambda SnapStart 執行時期勾點 (Java)
<a name="snapstart-runtime-hooks-java"></a>

您可以在 Lambda 建立快照之前或 Lambda 從快照恢復函數之後，使用執行階段掛鉤來實作程式碼。執行階段掛鉤可做為開放原始碼 Coordinated Restore at Checkpoint (CRaC) 專案的一部分使用。目前正在針對 [Java 開發套件 (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>` - 若要接收檢查點和還原的通知，必須透過 `Context` 註冊 `Resource`。
+ `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()`) 執行程式碼。此處理常式也會向執行階段管理的全域 `Context` 註冊 `Resource`。

**注意**  
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 );
```