Skip to main content

kemal-sse

Real-time Server-Sent Events (SSE) streaming in Kemal 1.12+, following established project patterns.

ソース情報

リポジトリ
kemalcr/kemal
ソースの最終更新活動
2026年8月29日 16:35
検出された SKILL.md の言語
英語
スター
3,923
フォーク
206

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
kemal-sse
description
Real-time Server-Sent Events (SSE) streaming in Kemal 1.12+, following established project patterns.
license
MIT
# Kemal Server-Sent Events (SSE) This skill provides expert guidance on implementing real-time unidirectional event streaming using Kemal's built-in `sse` helper (available in Kemal 1.12.0+). ## Version Notes - `sse` route helper and `Kemal::EventStream` (named events, `id:`, `retry:`): since Kemal 1.12.0. - SSE injection protection (CR/LF rejected in `event`/`id`, CRLF normalization in `data` and comments) and the `retry` field Int32 overflow fix: since Kemal 1.13.0. - Negative `retry` spans are omitted from the output (clients discard non-digit values): unreleased, after Kemal 1.13.0. ## Core Mandates - **SSE Route Definition (Kemal 1.12.0+):** Use the `sse` helper block to define an SSE endpoint: ```crystal sse "/events" do |stream, env| stream.send("hello world") end ``` - **Sending Named Events & Security:** Pass `event`, `id`, and optional `retry` (`Time::Span`) keyword arguments: ```crystal sse "/notifications" do |stream, env| stream.send({"message" => "New alert"}.to_json, event: "alert", id: 101, retry: 5.seconds) end ``` *Security Note (Kemal 1.13.0+)*: `Kemal::EventStream` prevents SSE injection by rejecting raw newlines in `event` and `id` arguments, and automatically normalizes CRLF sequences in `data` and `comment`. - **Streaming Loops & Channels:** Use Crystal channels or keep-alive loops for streaming events: ```crystal sse "/stream" do |stream, env| loop do sleep 1.seconds stream.send(Time.utc.to_s, event: "time") rescue IO::Error break # Connection closed by client end end ``` ## Patterns from Source Code ### Real-Time Live Updates with Channel / Loop ```crystal require "kemal" sse "/live-ticks" do |stream, env| count = 0_i64 loop do count += 1 stream.send( {"count" => count, "timestamp" => Time.utc.to_s}.to_json, event: "tick", id: count ) sleep 1.seconds rescue IO::Error # Client disconnected, gracefully terminate streaming loop break end end Kemal.run ``` ### Pub/Sub Broadcasting via SSE Stream Manager ```crystal require "kemal" class SseHub @streams = Array(Kemal::EventStream).new @mutex = Mutex.new def register(stream : Kemal::EventStream) @mutex.synchronize { @streams << stream } end def unregister(stream : Kemal::EventStream) @mutex.synchronize { @streams.delete(stream) } end def broadcast(data : String, event : String? = nil) @mutex.synchronize do @streams.reject! do |stream| begin stream.send(data, event: event) false rescue IO::Error true # Remove closed connections end end end end end HUB = SseHub.new sse "/subscribe" do |stream, env| HUB.register(stream) # Block while connection remains open begin sleep ensure HUB.unregister(stream) end end post "/publish" do |env| message = env.params.body["message"]? || "" HUB.broadcast(message, event: "news") env.json({status: "ok"}) end Kemal.run ``` ## Best Practices - **Connection Cleanup:** Always handle client disconnects gracefully by rescuing `IO::Error` or using an `ensure` block. - **Content Type:** Kemal automatically sets `Content-Type: text/event-stream` and `Cache-Control: no-cache` headers for SSE routes. - **JSON Serialization:** Convert Crystal data structures to JSON strings using `.to_json` before passing to `stream.send(...)`. - **API Response Helpers:** For JSON response formatting and error handling on companion HTTP routes (e.g. `post "/publish"`), follow the patterns in [`kemal-json`](../kemal-json/SKILL.md). - **Prefer SSE over WebSockets for Uni-directional Feeds:** Use SSE for live log feeds, dashboard metrics, and notifications where full bi-directional socket protocol overhead is unnecessary. ## When to Use - When building real-time dashboards, log streaming, or live notification feeds. - When client-to-server responses are handled via standard HTTP POST routes, while server-to-client updates stream via HTTP `text/event-stream`.
GitHubで見る