Go: context canceled
GoでContextがキャンセルされた際のエラー原因と解決策
概要
GoのContextがキャンセルまたはタイムアウトした際に発生するエラーです。
エラーメッセージ
``` context canceled context deadline exceeded ```
原因
- 明示的なキャンセル: cancel()の呼び出し
- タイムアウト: context.WithTimeoutの期限切れ
- 親コンテキストのキャンセル: 親がキャンセルされると子も連動
- HTTPリクエストの中断: クライアントが接続を切断
解決策
1. Contextを適切に伝播
```go func handler(w http.ResponseWriter, r *http.Request) { ctx := r.Context()
result, err := doWork(ctx)
if err != nil {
if errors.Is(err, context.Canceled) {
// クライアントが切断した
return
}
http.Error(w, err.Error(), 500)
return
}
json.NewEncoder(w).Encode(result)
}
func doWork(ctx context.Context) (Result, error) { select { case <-ctx.Done(): return Result{}, ctx.Err() case result := <-workChan: return result, nil } } ```
2. タイムアウトを設定
```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel()
// HTTPリクエスト req, _ := http.NewRequestWithContext(ctx, “GET”, url, nil) resp, err := client.Do(req) if err != nil { if errors.Is(err, context.DeadlineExceeded) { log.Println(“Request timed out”) } return err } ```
3. グレースフルシャットダウン
```go func main() { ctx, cancel := context.WithCancel(context.Background())
// シグナルハンドリング
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigChan
cancel()
}()
if err := run(ctx); err != nil && !errors.Is(err, context.Canceled) {
log.Fatal(err)
}
} ```
4. データベースクエリでの使用
```go ctx, cancel := context.WithTimeout(ctx, 3*time.Second) defer cancel()
rows, err := db.QueryContext(ctx, “SELECT * FROM users WHERE id = ?”, id) if err != nil { if errors.Is(err, context.DeadlineExceeded) { return nil, fmt.Errorf(“query timed out: %w”, err) } return nil, err } ```
よくある間違い
- defer cancel() を忘れてリソースリーク
- context.Background() を常に使う
- エラーの種類を確認しない
関連エラー
関連エラー
Go の他のエラー
この記事は役に立ちましたか?