The post has been translated automatically. Original language: Russian
Problem
Rails traditionally runs in a thread-based model (Puma). With LLM requests, this is expensive: the thread is blocked waiting for a response from OpenAI/Anthropic in seconds while it could serve other clients.
Falcon is the main player
Falcon is a multi-process, multi-fiber Rack compatible HTTP server built on async, async-container and async-http. Each request is executed in lightweight fiber and can be blocked on upstream requests without stopping the entire server process.
At Kaigi on Rails 2025, Samuel Williams (author of Falcon) showed the possibility of 1 million WebSocket connections per process via fibers, and demonstrated an LLM demo on top of async WebSocket.
What Falcon provides for LLM applications:
Unlike traditional thread-based job processors that lock up during long LLM operations, Async::Job uses fibers for thousands of competitive tasks. Minimum configuration: add gem 'falcon' and gem 'async-job-adapter-active_job', specify config.active_job.queue_adapter = :async_job — and one process handles thousands of competitive LLM operations without additional infrastructure.RubyLLM + Async: It works out of the box
RubyLLM automatically becomes non-blocking under Falcon, because Net::HTTP knows how to concede control to fibers. Competitive LLM calls are written as simply as possible through the Async { } block. Streaming responses: SSE vs Turbo Streams
Two main approaches for streaming LLM responses in Rails:
SSE (Server-Sent Events) SSE is a simple and effective way to push data from the server to the browser in real time. Through POST requests with SSE, you can overcome URL length restrictions and securely transmit the history of the conversation with LLM.
Turbo Streams (Hotwire) In a Rails application with Hotwire/Turbo, you can stream updates from the background job. SSE is the most organic option for streaming LLM text responses.Pitfalls: the order of messages
Neither the standard Action Cable nor the async-cable provide a 100% guarantee of the order of messages under load due to the nature of the threads. A more reliable option is to implement reordering on the client side, although this requires significantly more work.
async-cable is an alternative implementation of Action Cable based on Async, supports HTTP/1 and HTTP/2 WebSockets with higher bandwidth. Rack 3 bidirectional streaming opens patterns similar to SSE.
Проблема
Rails традиционно работает в thread-based модели (Puma). При LLM-запросах это дорого: поток заблокирован на ожидание ответа от OpenAI/Anthropic секундами, пока мог бы обслуживать других клиентов.
Falcon — главный игрок
Falcon — это multi-process, multi-fiber Rack-совместимый HTTP-сервер, построенный на async, async-container и async-http. Каждый запрос выполняется в легковесном fiber-е и может блокироваться на upstream-запросах, не останавливая весь серверный процесс.
На Kaigi on Rails 2025 Samuel Williams (автор Falcon) показал feasibility 1 миллиона WebSocket-соединений на процесс через fibers, и продемонстрировал LLM demo поверх async WebSocket.
Что даёт Falcon для LLM-приложений:
В отличие от традиционных thread-based job-процессоров, которые блокируются во время долгих LLM-операций, Async::Job использует fibers для тысяч конкурентных задач. Минимальная конфигурация: добавить gem 'falcon' и gem 'async-job-adapter-active_job', указать config.active_job.queue_adapter = :async_job — и один процесс обрабатывает тысячи конкурентных LLM-операций без дополнительной инфраструктуры.RubyLLM + Async: это работает "из коробки"
RubyLLM автоматически становится non-blocking под Falcon, потому что Net::HTTP умеет уступать управление fibers. Конкурентные LLM-вызовы пишутся максимально просто через Async { } блок. Стриминг ответов: SSE vs Turbo Streams
Два основных подхода для streaming LLM-ответов в Rails:
SSE (Server-Sent Events) SSE — простой и эффективный способ пушить данные с сервера в браузер в реальном времени. Через POST-запросы с SSE можно преодолеть ограничения по длине URL и безопасно передавать историю диалога с LLM.
Turbo Streams (Hotwire) В Rails-приложении с Hotwire/Turbo можно транслировать stream-обновления из background job. SSE — наиболее органичный вариант для стриминга текстовых ответов LLM.Подводные камни: порядок сообщений
Ни стандартный Action Cable, ни async-cable не дают 100% гарантии порядка сообщений под нагрузкой из-за природы потоков. Более надёжный вариант — реализовать переупорядочивание на стороне клиента, хотя это требует значительно больше работы.
async-cable — альтернативная реализация Action Cable на базе Async, поддерживает HTTP/1 и HTTP/2 WebSockets с более высокой пропускной способностью. Rack 3 bidirectional streaming открывает паттерны, аналогичные SSE.