インスタンスライフサイクルフックは、関数インスタンスが起動または停止する際にカスタムロジックを実行します。このトピックでは、カスタムイメージを使用する関数に Initializer フックと PreStop フックを実装および設定する方法を説明します。
背景情報
関数インスタンスのライフサイクルには、Initializer フックと PreStop フックが含まれます。Function Compute は、関連するインスタンスのライフサイクルイベントが発生した際に、対応するフックを呼び出します。
Initializer フックには、コードの呼び出し と 命令の実行 の 2 種類のタイプがあります。現在、命令の実行 タイプの Initializer フックは、GPU アクセラレーション関数のみでサポートされています。詳細については、「インスタンスライフサイクルの設定」をご参照ください。
インスタンスライフサイクルフックの課金ルールは、通常の呼び出しリクエストの課金ルールと同じです。
フックのログに関する詳細については、「インスタンスライフサイクルフックのログの表示」をご参照ください。
フックのタイプ
Initializer フックは 2 つの実装タイプをサポートしています。次の表で、これらのタイプを比較します。
フックタイプ | メカニズム | 適用範囲 |
コードの呼び出し | Function Compute が関数に HTTP リクエストを送信します。ビジネスコードがそのリクエストに応答します。 | Initializer フックと PreStop フック |
命令の実行 | Function Compute が設定されたシェルコマンドまたはスクリプトを実行します。終了コードによって成功か失敗かが決まります。 | GPU アクセラレーション関数専用の Initializer フック |
Initializer フックには、2 つのタイプのうち 1 つだけを設定できます。
フックの実装
以下のセクションでは、各フックタイプの実装方法を説明します。
コードの呼び出し
「コードの呼び出し」タイプのフックを設定すると、Function Compute は関数インスタンスの起動時または停止時に HTTP リクエスト POST /initialize または GET /pre-stop を関数に送信します。ビジネスコードがこのリクエストに応答する必要があります。
パス | リクエスト | 期待されるレスポンス |
(任意) POST | リクエストボディ:なし。リクエストヘッダー:共通リクエストヘッダー。詳細については、「Function Compute 共通リクエストヘッダー」をご参照ください。 | レスポンスボディ:関数の Initializer によって返される値。ステータスコード:2xx は成功、非 2xx は失敗を示します。Initializer フックがタイムアウトまたは失敗した場合、サーバーは常に HTTP 200 ステータスコードを返します。 |
(任意) GET | リクエストボディ:なし。リクエストヘッダー:共通リクエストヘッダー。詳細については、「Function Compute 共通リクエストヘッダー」をご参照ください。 | レスポンスボディ:関数の PreStop によって返される値。
|
[パス] 列が (任意) とマークされているのは、各フックがオプション設定であるためです。作成する関数に Initializer を設定しない場合、/initialize を実装する必要はありません。この場合、HTTP サーバーが /initialize を実装していても、コード内の /initialize ロジックが呼び出されることはありません。PreStop についても同様です。
カスタムイメージで Initializer フックメソッドを使用するには、HTTP サーバーで POST メソッドを使用して /initialize パスのロジックを実装します。PreStop フックメソッドについても同様です。次のサンプルプログラムでは、Python 3.10 のカスタムランタイムを例として使用しています。
import os
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/initialize', methods=['POST'])
def init_invoke():
rid = request.headers.get('x-fc-request-id')
print("FC Initialize Start RequestId: " + rid)
# ここに独自の初期化ロジックを実装します
print("FC Initialize End RequestId: " + rid)
return "OK"
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def hello_world(path):
rid = request.headers.get('x-fc-request-id')
print("FC invoke Start RequestId: " + rid)
# ここに独自の呼び出しロジックを実装します
print("FC invoke End RequestId: " + rid)
return "Hello, World!", 200, [('Function-Name', os.getenv('FC_FUNCTION_NAME'))]
@app.route('/pre-stop', methods=['GET'])
def prestop_invoke():
rid = request.headers.get('x-fc-request-id')
print("FC PreStop Start RequestId: " + rid)
# ここに独自の PreStop ロジックを実装します
print("FC PreStop End RequestId: " + rid)
return "OK"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9000)フックコードは実行時に失敗することもあります。次の /initialize のサンプルは、2 つの典型的な失敗例と、それらに対する Function Compute の応答を示しています。各エラーコードのシステムの動作については、「フックのエラーコード」をご参照ください。
次の例では、ハンドラーが例外を発生させます。Function Compute はこの失敗を 500 エラーとして扱い、インスタンスを再起動します。
@app.route('/initialize', methods=['POST'])
def init():
raise Exception("hahaha")
return "OK", 200, []次の例では、ハンドラーが 404 ステータスコードを返します。Function Compute はリクエストを再送しません。
@app.route('/initialize', methods=['POST'])
def init():
return "OK", 404, []命令の実行 (GPU アクセラレーション関数のみ)
「命令の実行」タイプは、GPU アクセラレーション関数でのみ利用できます。
「命令の実行」タイプでは、Function Compute は関数インスタンスの起動後に設定されたシェルコマンドまたはスクリプトを実行します。終了コードが 0 の場合はフック命令が正常に実行されたことを示し、それ以外の終了コードは失敗を示します。
/bin/bash、/bin/sh、/bin/csh、/bin/zsh などのカスタムシェル実装を使用できます。使用するシェル実装が関数のランタイム環境でサポートされていることを確認してください。
Function Compute コンソールでは、/bin/bash と /bin/sh がプリセットオプションとして提供されています。次の例では /bin/sh を使用しています。このスクリプトは、初期化のヘルスチェックを実行します。curl を使用してローカルサービスにリクエストを送信し、jq を使用して出力をフォーマットします。両方のツールがランタイム環境で利用可能であることを確認してください。
#!/bin/sh
URL="http://localhost:7860"
REQUEST_PATH="sdapi/v1/txt2img"
JSON_DATA='{
"prompt": "",
"steps": 1,
"height": 8,
"width": 8
}'
temp_file=$(mktemp)
trap 'rm -f "$temp_file"' EXIT
if ! http_code=$(curl -s -w "%{http_code}" \
-H "Content-Type: application/json" \
-d "$JSON_DATA" \
-o "$temp_file" \
-X POST "$URL"/"$REQUEST_PATH"); then
echo "{\"status\": \"curl_error\", \"code\": $?}" \
| jq . >&2
exit 1
fi
response=$(<"$temp_file")
echo "http code $http_code"
if [ "$http_code" -eq 200 ]; then
echo "$response" | jq -r '.' || printf "%s\n" "$response"
exit 0
else
echo "$response" \
| jq -c 'if type == "object" then . else {raw: .} end' 2>/dev/null \
| jq -s '{status: "http_error", code: $code, response: .[0]}' \
--arg code "$http_code" \
>&2
exit 1
fiエラーの原因を特定しやすくするために、スクリプト内のエラー情報を標準エラー出力 (stderr) に書き込みます。たとえば、次のコードスニペットは、curl リクエストが失敗したときにエラー情報を書き込み、終了コードを 1 に設定します。失敗時の動作は同様です。命令が 0 以外の終了コードを返した場合、命令は再実行されず、システムは関連するエラーを返します。詳細については、「フックのエラーコード」をご参照ください。
if ! http_code=$(curl -s -w "%{http_code}" \
-H "Content-Type: application/json" \
-d "$JSON_DATA" \
-o "$temp_file" \
-X POST "$URL"/"$REQUEST_PATH"); then
echo "{\"status\": \"curl_error\", \"code\": $?}" \
| jq . >&2
exit 1
fiライフサイクルフックの設定
Function Compute コンソールにログインします。左側のナビゲーションペインで、関数管理 > 関数リスト を選択します。
上部メニューでリージョンを選択します。関数リスト ページで、対象の関数をクリックします。
関数の詳細ページで、設定 タブをクリックします。インスタンスの設定 セクションで 変更 をクリックします。
インスタンスの設定 パネルで、Initializer フックを設定します。[Initializer フック] スイッチをオンにし、ビジネス要件に基づいて [Initializer タイムアウト] を設定します。この例では、タイムアウトは
300秒です。[フックタイプ] で、次のいずれかのタイプを選択します。コードの呼び出し
フックを有効にすると、Function Compute はインスタンスの起動時に HTTP POST
/initializeリクエストを関数に送信します。ビジネスコードはリクエストに応答し、200 ステータスコードを返す必要があります。命令の実行
「命令の実行」タイプは、GPU アクセラレーション関数でのみ利用できます。
フックタイプとして [命令の実行] を選択し、[/bin/sh] などのシェル命令を選択します。コードエディターに初期化スクリプトを記述します。完全な例については、「命令の実行 (GPU アクセラレーション関数のみ)」をご参照ください。
(任意) PreStop フックを設定します。[PreStop フック] スイッチをオンにし、ビジネス要件に基づいて [PreStop タイムアウト] を設定します。この例では、タイムアウトは
3秒です。デプロイ をクリックします。
フックが有効になったことを確認します。関数を呼び出すか、関数の設定またはコードを更新して、インスタンスの作成と破棄をトリガーします。次に、「インスタンスライフサイクルフックのログの表示」の手順に従ってフックのログを確認します。
インスタンスライフサイクルフックのログの表示
[リアルタイムログ]、関数ログ、または 詳細ログ でフックの実行ログを確認できます。[呼び出しリクエストリスト] にはフックのログは表示されません。
「命令の実行」フックによって生成されたログは、関数ログに書き込むことができません。
関数ログ 機能を使用してフックのログを表示できます。
Function Compute コンソールにログインします。左側のナビゲーションペインで、関数管理 > 関数リスト を選択します。
上部メニューでリージョンを選択します。関数リスト ページで、対象の関数をクリックします。
関数の詳細ページで、テスト タブをクリックし、関数のテスト をクリックして、ログ > 関数ログ を選択します。
関数ログ タブで、関数の呼び出しログと Initializer フックのログを表示できます。次の例はログを示しています。
2024-06-26 10:59:23FC Initialize Start RequestId: 529eab23-9b3a-4ffc-88c8-9a686*******
2024-06-26 10:59:23FC Initialize End RequestId: 529eab23-9b3a-4ffc-88c8-9a686*******
2024-06-26 10:59:25FC Invoke Start RequestId: 1-667b840c-15c49df0-b7dc1*******
2024-06-26 10:59:25FC Invoke End RequestId: 1-667b840c-15c49df0-b7dc1*******各関数インスタンスは一定期間キャッシュされ、すぐに破棄されないため、PreStop フックのログはすぐには利用できません。PreStop フックをすぐにトリガーするには、関数の設定またはコードを更新します。更新が完了したら、再度 関数ログ を確認して PreStop フックのログを表示します。次の例はログを示しています。
2024-06-26 11:04:33FC PreStop Start RequestId: c4385899-f071-490e-a8b7-e33c5*******
2024-06-26 11:04:33FC PreStop End RequestId: c4385899-f071-490e-a8b7-e33c5*******フックのエラーコード
コードの呼び出し
エラーコード | 説明 |
400 | 関数の Initializer フックが失敗して 400 または 404 を返した場合、リクエストは再送されませんが、呼び出しが成功するまでシステムはリトライを続けます。関数の PreStop フックが失敗して 400 または 404 を返した場合、関数インスタンスの凍結と停止には影響しません。 |
404 | |
500 | Function Compute はインスタンスを再起動します。 |
命令の実行
命令が 0 以外の終了コードを返した場合、命令は再実行されず、システムは関連するエラーを返します。スクリプトがエラー情報を stderr に書き込む場合、その出力を使用して失敗の原因を特定できます。