Server-Sent Events on Rails
RailsでServer-Sent Eventsを実装するにはActionController::Liveを使う
https://api.rubyonrails.org/v8.0/classes/ActionController/Live.html
このmoduleをincludeしたcontroller内のすべてのactionで response.stream が使える
レスポンスヘッダでtext/event-streamを宣言したあと、 response.stream.write で送信したデータを書き込む
サーバーサイド
code:ruby
class MyController < ActionController::Base
include ActionController::Live
def stream
response.headers'Content-Type' = 'text/event-stream'
response.stream.write("event: connected\n")
response.stream.write("data: #{JSON.dump({message: 'connected', thread_id: Thread.current.object_id})}\n\n")
# 何らかの処理
response.stream.write("event: result\n")
response.stream.write("data: #{JSON.dump({
message: 'Process completed successfully!',
timestamp: Time.now.to_i,
thread_id: Thread.current.object_id,
processing_time: processing_time
})}\n\n")
ensure
response.stream.close
end
end
クライアント
ほぼMozillaに書いてある通り
onmessageでイベントハンドラを書くか、addEventListenerでカスタムイベントのハンドラを書く
code:js
// Railsの提供するAPIに向ける
const eventSource = new EventSource("/events/stream");
// メッセージ受信時
eventSource.onmessage(function(e) {
const data = JSON.parse(e.data);
// 受け取ったdataを処理する
});
// カスタムイベント: 接続
eventSource.addEventListener('connected', function(e) {
const data = JSON.parse(e.data);
// 受け取ったdataを処理する
});
// カスタムイベント: 接続
eventSource.addEventListener('connected', function(e) {
const data = JSON.parse(e.data);
// 受け取ったdataを処理する
});
// カスタムイベント: 結果
eventSource.addEventListener('result', function(e) {
const data = JSON.parse(e.data);
// 受け取ったdataを処理する
// 接続を閉じる
eventSource.close();
});
2025-04
https://www.aha.io/engineering/articles/streaming-llm-responses-rails-sse-turbo-streams
SSEでなくHotwire, Turbo Streamを使う方法もある
本記事はそれぞれのメリット、デメリットについて詳しい