coder / coder/websocket

Add lightweight write deadlines to Conn

オープン
#572 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Go
スター
5.5k
フォーク
372
PR マージ指標
30日以内にマージされた PR はありません

説明

### Problem

Long-lived WebSocket servers often need every outbound write to be bounded. With `v1.8.15`, the main API requires creating a deadline context for every message:

```go
package main

import (
"context"
"log"
"net/http"
"time"

"github.com/coder/websocket"
)

func main() {
http.HandleFunc("/", serve)
log.Fatal(http.ListenAndServe(":8080", nil))
}

func serve(w http.ResponseWriter, r *http.Request) {
c, err := websocket.Accept(w, r, nil)
if err != nil {
return
}
defer c.CloseNow()

connCtx := c.CloseRead(r.Context())
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()

for {
select {
case <-connCtx.Done():
return
case <-ticker.C:
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
err := c.Write(ctx, websocket.MessageText, []byte(`{"type":"event"}`))
cancel()
if err != nil {
return
}
}
}
}
```

Using `context.Background()` avoids the timeout-related allocations added around each frame, but also removes the bounded-write guarantee.

`websocket.NetConn` exposes `SetWriteDeadline`, but it is a full bidirectional adapter. It creates read and write contexts, timers, and locks, and calls `SetReadLimit(-1)` even when only its write side is needed.

A loopback benchmark with `v1.8.15` on Go 1.27rc2 produced:

| Strategy | Write path | Connection construction |
|---|---:|---:|
| `context.WithTimeout` | 1304 B/op, 12 allocs/op | no extra adapter |
| `NetConn.SetWriteDeadline` | 664 B/op, 5 allocs/op | 848 B, 13 allocs |

The write measurements use the same client reader, so the allocation difference is the relevant result. At high connection counts, the fixed `NetConn` cost is material.

### Request

Could `*websocket.Conn` provide a lightweight write-only deadline mechanism, for example `SetWriteDeadline(time.Time)` or an equivalent API?

Ideally it would:

- reuse connection-owned deadline state instead of allocating a timer context per write;
- bound both write-lock acquisition and the underlying write;
- preserve the current behavior where a timed-out write closes the WebSocket;
- remain safe with concurrent `Ping`, `Close`, and data writes;
- avoid creating read-side state or changing the configured read limit;
- allow zero time to clear the deadline.

Related: #252 discusses the same API direction for read deadlines.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

まず *websocket.Conn の書き込みパスと websocket.NetConn の deadline 処理を調査し、その後、read-deadline の方向性について issue #252 を読んでください。完了条件は、ロックの取得と書き込みを制限し、タイムアウト時のクローズ動作を維持し、並行操作に対して安全で、読み取り側の状態を持たず、ゼロの時刻でクリアされる、書き込み専用の deadline 機構です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
go
領域
backend-api-design, networking
issue の種類
機能追加
難易度
5/5
見積もり時間
1週間以上
活発さ
静か
明瞭さ
おおむね明確
初心者へのやさしさ
45/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。