サーバーの準備
main.go
package main
import (
"log"
"net/http"
"time"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// 擬似的な長い処理を実行
log.Println("processing request")
select {
case <-time.After(5 * time.Second): // 5秒後に処理が完了するとする
// リクエストが成功したらレスポンスを返す
w.Write([]byte("Request processed"))
case <-ctx.Done():
// contextがキャンセルされたらエラーをログに出力
err := ctx.Err()
log.Println("request cancelled:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
// サーバーを8080ポートで起動
log.Println("server started")
http.ListenAndServe(":8080", nil)
}
httpサーバーを起動させます。
Server side
$ go run main.go
2023/11/05 22:49:46 server started
リクエストを送信する
キャンセルされるリクエストの送信
curlでサーバーで指定されているポート番号8080に対してリクエストを送り、1秒後にキャンセルするコマンドを打ちます。
Client side
$ curl http://localhost:8080 & PID=$!; sleep 1; kill $PID
[1] 91299
[1] + terminated curl http://localhost:8080
そうすると、以下のようにキャンセルされることがわかりました。
Server side
2023/11/05 22:53:37 processing request
2023/11/05 22:53:38 request cancelled: context canceled
キャンセルされないリクエストの送信
ちなみに、クライアントサイドで5秒より多く待つことで、サーバー側でキャンセルされないことも確認できます。
Client side
$ curl http://localhost:8080 & PID=$!; sleep 6
[1] 91373
Request processed[1] + done curl http://localhost:8080
おまけ curlの解説
curl http://localhost:8080 & PID=$!; sleep 1; kill $PID
このコマンドは、curl
を用いてhttp://localhost:8080
にHTTPリクエストを送信し、1秒後にそのプロセスを終了(kill)させます。
-
curl http://localhost:8080 &
:-
curl
で、指定されたURL(この場合はhttp://localhost:8080
)に対してHTTPリクエストを送信します。 -
&
はこのコマンドをバックグラウンドで実行するためのものです。つまり、curl
コマンドは新しいバックグラウンドプロセスとして開始されます。
-
-
PID=$!
:-
$!
は最後にバックグラウンドで実行されたプロセスのプロセスID(PID)を表します。 -
PID=$!
はこのPIDを変数PID
に代入しています。これにより、後でこのプロセスを特定し終了させることができます。
-
-
sleep 1
:-
sleep 1
は、コマンドが1秒間待機するようにします。これはcurl
コマンドに少し時間を与えてサーバーにリクエストを送信するためのものです。
-
-
kill $PID
:-
kill
コマンドは指定されたPIDのプロセスを終了します。 -
kill $PID
は、先ほどcurl
コマンドによって生成されたバックグラウンドプロセスを終了させます。
-