recover の使用
CoddyのGOジャーニー「論理とフロー」セクションの一部 — レッスン 43/68。
panic はプログラムを即座に停止させますが、Go は recover 関数を通じて制御を取り戻す方法を提供しています。recover 関数を使用すると、パニックをキャッチして適切に処理できるようになり、プログラム全体がクラッシュするのを防ぐことができます。
しかし、recover には非常に具体的な要件があります。それは、遅延関数(deferred function)内でのみ使用できるということです。パニックが発生すると、Go はプログラムが終了する前にすべての遅延関数を実行し、recover がパニックを捕捉する機会を与えます。
func riskyFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong!")
}recover 関数は、panic に渡された値を返します。パニックが発生しなかった場合は nil を返します。これにより、パニックが発生したかどうかを確認し、エラーのログ記録やクリーンアップ操作の実行など、適切なアクションを取ることができます。
panicと同様に、Goではrecoverは控えめに使用されるべきです。これは、単一のリクエストによるパニックがサーバー全体をクラッシュさせるのを防ぎ、他のリクエストへのサービス提供を継続できるようにしたいウェブサーバーのようなシナリオで最も一般的に見られます。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
チャレンジ
簡単recover を使用してパニックを適切に処理し、サーバー全体のクラッシュを防ぐウェブサーバーのリクエストハンドラーを構築してください。このチャレンジでは、遅延関数(deferred function)内で recover を使用してパニックをキャッチし、サーバーの安定性を維持する方法を学びます。
2つの入力を受け取ります:
"endpoint,method,action"形式のリクエスト詳細を含む文字列(例:"/api/users,GET,process")"server_name,max_requests"形式のサーバー設定を含む文字列(例:"WebServer,100")
あなたのタスクは以下の通りです:
- 最初の入力をカンマで分割し、endpoint、method、action を取得して解析する
- 2番目の入力をカンマで分割し、server name と max requests を取得して解析する
- max requests の文字列を整数に変換する
- endpoint、method、action、server name をパラメータとして受け取る
handleRequestという関数を作成する handleRequest内に、recoverを使用してパニックをキャッチする遅延関数を追加する:- パニックが回復された場合(recover が non-nil を返す場合)、
"Server [server_name] recovered from panic: [panic_value]"と出力する - パニックの処理後、
"Request handling completed safely"と出力する
- パニックが回復された場合(recover が non-nil を返す場合)、
- 遅延関数の後で、action に基づいてリクエスト処理をシミュレートする:
- action が
"process"の場合:"Processing [method] request to [endpoint]"と出力する - action が
"panic_nil"の場合:"Attempting dangerous operation"と出力し、panic("nil pointer access")を呼び出す - action が
"panic_overflow"の場合:"Attempting resource allocation"と出力し、panic("memory overflow")を呼び出す - action が
"panic_timeout"の場合:"Attempting database connection"と出力し、panic("connection timeout")を呼び出す - それ以外の action の場合:
"Unknown action: [action]"と出力し、panic("invalid action")を呼び出す
- action が
- main 関数で、サーバーの起動メッセージ
"Starting [server_name] with max [max_requests] requests"を出力する - 解析したパラメータを使用して
handleRequest関数を呼び出す - 関数呼び出しの後、サーバーのステータス
"Server [server_name] is still running"を出力する - 最後に、サマリーを出力する:
"Server Summary:""Name: [server_name]""Max Requests: [max_requests]""Last Request: [method] [endpoint]""Action Performed: [action]""Status: Operational"
入力文字列をカンマで分割するには strings パッケージを、max requests の文字列を整数に変換するには strconv パッケージを使用してください。このチャレンジは、recover によってサーバーが予期しないパニックを適切に処理し、個別のリクエストの失敗がシステム全体をダウンさせるのを防ぐ方法を示しています。
チートシート
recover関数を使用すると、パニックをキャッチして適切に処理し、プログラムのクラッシュを防ぐことができます。
recoverは、遅延関数(deferred function)内でのみ使用できます:
func riskyFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong!")
}recover関数は、panicに渡された値を返します。パニックが発生しなかった場合はnilを返します。これにより、パニックが発生したかどうかを確認し、適切なアクションを実行できます。
recoverは、単一のリクエストによるパニックでサーバー全体がクラッシュするのを防ぐために、Webサーバーで一般的に使用されます。
自分で試してみよう
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// 入力を読み込む
var requestDetails string
var serverConfig string
fmt.Scanln(&requestDetails)
fmt.Scanln(&serverConfig)
// リクエストの詳細を解析する
requestParts := strings.Split(requestDetails, ",")
endpoint := requestParts[0]
method := requestParts[1]
action := requestParts[2]
// サーバー設定を解析する
configParts := strings.Split(serverConfig, ",")
serverName := configParts[0]
maxRequests, _ := strconv.Atoi(configParts[1])
// TODO: 以下にコードを記述してください
// リカバリメカニズムを備えた handleRequest 関数を作成する
// サーバーの起動メッセージを表示する
// handleRequest 関数を呼び出す
// サーバーのステータスと概要を表示する
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
論理とフローのすべてのレッスン
7エラーハンドリング詳説
カスタムエラー型%w によるエラーのラッピングerrors.Is によるアンラップerrors.As によるアンラップpanic の理解recover の使用まとめ:安全な除算