I am writing a websocket service in golang. The program use gollira websocket to accept ws request, and in each request handler, it listen to rabbitmq queue for messages.
The problem is, when i close browser window, the handler thread is still running, i guess there is an mechanism to be notified when connection disconnected.
I try to listen to channel request.Context().Done(), when i doesn't work.
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
"github.com/streadway/amqp"
)
var (
addr = "localhost:9999"
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
)
var conn *amqp.Connection
func watch(w http.ResponseWriter, r *http.Request) {
ns := r.URL.Query().Get("ns")
if ns == "" {
return
}
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()
err = ch.ExchangeDeclare(
"notify", // name
"fanout", // type
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare an exchange")
q, err := ch.QueueDeclare(
"", // name
false, // durable
false, // delete when usused
true, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue")
err = ch.QueueBind(
q.Name, // queue name
ns, // routing key
"dsm_tasks_notify", // exchange
false,
nil)
failOnError(err, "Failed to bind a queue")
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer")
for {
select {
case d := <-msgs:
err = c.WriteMessage(websocket.TextMessage, d.Body)
if err != nil {
log.Println("write:", err)
break
}
case <-r.Context().Done():
log.Println("Disconnect")
return
}
}
}
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
}
func main() {
var err error
conn, err = amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
http.HandleFunc("/watch", watch)
log.Fatal(http.ListenAndServe(addr, nil))
}