Penpotのリアルタイム性を極限まで引き出す:社内プロキシ環境を突破するWebSocket/SSE深層アーキテクチャ
「デザインは共同作業である」――この概念を Penpot はオープンソースという土俵で完璧に体現した。しかし、そのリアルタイム協調編集を支える通信レイヤーは、多くのエンタープライズ環境において「ブラックボックス」として恐れられている。
プロキシの背後で頻発する接続断、あるいはメモリを喰いつぶす接続セッション。これらは単なるネットワーク設定のミスではない。プロトコルスタックの理解不足が引き起こす必然だ。今日は、Penpotの心臓部であるWebSocket/SSE通信を掌握し、いかなる過酷なネットワーク環境下でも「爆速」を維持するための設計思想を伝授する。
—
1. リアルタイム協調のエンジン:なぜPenpotは「切れる」のか
Penpotは、WebSocket (ws://) による双方向通信と、Server-Sent Events (SSE) による状態更新のプッシュを組み合わせることで、ミリ秒単位の同期を実現している。
社内プロキシやNginx等のリバースプロキシで接続が切断される主な原因は以下の3点だ。
1. タイムアウトの乖離: プロキシがアイドル接続と判断してセッションを破棄している(Keep-aliveの不一致)。
2. バッファリング: プロキシがSSEのチャンクを溜め込んでしまい、即時性を殺している。
3. プロトコルアップグレードの拒絶: HTTP/1.1からWebSocketへのアップグレードヘッダーが適切にフォワードされていない。
—
2. Nginxによる「完全透過」プロキシ構成の設計
Penpotをプロダクション運用する際、フロントに立つNginxの設定がすべてを決める。以下の設定は、リアルタイム性を損なわず、かつ堅牢性を担保するための「最適解」だ。
Penpot専用のUpstreamおよびプロキシ設定
upstream penpot_backend {
server penpot-backend:6060;
keepalive 32; # バックエンドとの接続を維持し、ハンドシェイクのオーバーヘッドを排除する
}
server {
# … SSL設定などは適宜 …
location /api/ws {
proxy_pass http://penpot_backend;
# WebSocketプロトコルのハンドシェイクを正しく継承
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “Upgrade”;
# 接続のタイムアウトを極限まで引き延ばす
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
# バッファリングを無効化(リアルタイム性を確保)
proxy_buffering off;
}
location /api/events {
proxy_pass http://penpot_backend;
# SSE用のヘッダー制御
proxy_set_header Connection ”;
proxy_http_version 1.1;
chunked_transfer_encoding on;
proxy_buffering off;
proxy_cache off;
}
}
—
3. DevOpsハック:CLIによる自動ヘルスチェックと最適化
単に設定を書くだけで満足してはいけない。エンジニアたるもの、システムの状態を常に観測し、閾値を超えた瞬間に再起動や再接続を自動化すべきだ。
PenpotのWebSocket接続が健康であるかを監視するGoの簡易スクリプト(抜粋)を共有する。これをサイドカーとして実行し、接続が安定しない場合にメトリクスを吐き出す仕組みを構築せよ。
// 接続監視・再接続エージェントの断片
func monitorConnection(url string) {
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
log.Fatalf(“接続不可: %v”, err)
}
defer conn.Close()
// 接続維持用のPing/Pongハンドラ
conn.SetPingHandler(func(appData string) error {
return conn.WriteControl(websocket.PongMessage, []byte(appData), time.Now().Add(time.Second))
})
// 接続の遅延を計測してPrometheusへメトリクスを送信するロジックをここに組み込む
}
—
4. パフォーマンス最適化の極意:メモリとネットワークの均衡
Penpotの協調編集は、クライアントサイドのメモリ消費が激しい。以下のハックを適用することで、大規模なデザインファイルでもブラウザを落とさないチューニングが可能だ。
- レンダリングパイプラインの分離: コンポーネントツリーが巨大化した場合、DOMの更新頻度がボトルネックになる。ブラウザのDevToolsで `Rendering` パネルを確認し、不要なレイアウト再計算が発生していないか監視せよ。
- アセットの最適化: 外部APIを通じてアセットを注入する場合、`Blob` ではなく `ArrayBuffer` を活用し、メインスレッドをブロックしないWeb Workerでの前処理を推奨する。
—
結びに:ツールを「使わされる」立場から「掌握する」立場へ
Penpotは単なるFigmaの代用品ではない。インフラをコード化し、通信を制御し、協調作業のプロトコルを理解する者にとっては、最強の「デザインOS」になり得るポテンシャルを秘めている。
プロキシの問題で躓いている時間は無駄だ。ネットワークスタックを理解し、Nginxをチューニングし、独自の監視エージェントを構築する。その先にあるのは、遅延のない、流れるような共同設計体験だ。
君たちが設計するのはUIだけではない。UIを届けるための「パイプライン」そのものを設計せよ。それが、真のプロダクトエンジニアの仕事だ。