📝
サクッとロングポーリングを試す
お知らせのようなリアルタイム性が求められる(こともある)機能実装をしたい場合、
websocket
やgRPC
だと工数やアプリケーションの構成的にヘビーな場合があります
代替のシンプルな方法としてロングポーリングも頭の片隅に入れておきたいです
お知らせを例にすると
1, client
はserver
へ"お知らせ"を取得するためのhttpリクエストを行う
2, server
は新規の"お知らせ"があるまでレスポンスを返さず保留する
3, server
は新規の"お知らせ"を検知するとレスポンスを返す
4, client
はserver
から"お知らせ"を受け取る
5, 1~4をループ
というのがロングポーリングです
メリットは、
・ポーリングと比べてリアルタイム性が高いかつ、サーバーへの負荷が低い
・websocket
やgRPC
と比べると前提条件があまり無く、実装が容易
デメリットは、
・HTTPコネクションを1つ占領する
・データのやりとりは結局個別のHTTP通信なので、websocket
やgRPC
に比べヘッダーや認証のオーバーヘッドがある
・上記の理由から頻繁に配信されるデータを扱う場合にはリアルタイム性を担保しずらい
あたりだと私は理解してます
他にもこんなのあるよというのがあれば教えてもらえると嬉しいです
試す
せっかくなのでGoでサクッと試してみます
main.go
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/long_polling", longPolling)
http.HandleFunc("/send", send)
port := "80"
log.Printf("Listening on port %s", port)
if err := http.ListenAndServe(fmt.Sprintf(":%v", port), nil); err != nil {
log.Panicln("Serve Error:", err)
}
}
var msgCh = make(chan string)
func send(w http.ResponseWriter, r *http.Request) {
msgCh <- "hello"
w.Write([]byte("ok"))
}
func longPolling(w http.ResponseWriter, r *http.Request) {
// msgChへ値が送信されるまで処理をブロック
msg := <-msgCh
w.Write([]byte(msg))
}
// consoleA
% curl http://localhost:80/long_polling
// "/send"へリクエストが来るまでレスポンスは保留される
=> hello
// consoleB
% curl http://localhost:80/send
=> ok
Goの場合channel
を利用すると簡単に実装できますね
本番ではRedis
のPub/Subなど使うといいと思います
Discussion