Brian Cardarella
Real-time is just one of the areas where Node.js has outpaced Rails
Rails was the innovator and is now playing catch-up
Can Rails Scale?
Can Rails Scale?
(its features)
Rails 4 is now fully concurrent, there is no full-stack lock on a request. If you use a concurrent server like Puma you can handle many requests at a time with a single process.
- Nick Gauthier
thread = Thread.new do
100.times do
puts 'Here!'
end
end
puts 'Over here too!'
Simple race condition example
poll = function() {
$.ajax({
url: '/chat.json',
data: { last_time: getLastTime() }
}).done(function(data) {
// handle data
setTimeout(poll, 1000);
});
}
class ChatController < ActionController::Base
def index
render json: { chat: Chat.history_from(params[:last_time]) }
end
end
class ChatController < ActionController::Base
include ActionController::Live
def index
Thread.new do
ChatStreamer.run(response.stream)
end
end
end
The stream object is meant to quack like an IO object
class MyController < ActionController::Base
include ActionController::Live
def index
100.times {
response.stream.write "hello world\n"
}
response.stream.close
end
end
def index
100.times {
response.headers['Content-Type'] = 'text/event-stream'
response.stream.write "event: time\n"
data = JSON.dump({ time: Time.now })
response.stream.write "#data: {data}\n\n"
sleep 1
}
response.stream.close
end
var source = new EventSource('/browser');
source.addEventListener('time', function(event) {
// handle event
});
env['rack.hijack?']
=> true
env['rack.hijack'].call
=> <TCPSocket:XXXX>
env['rack.hijack_io']
=> <TCPSocket:XXXX>
gem 'websocket', github: 'imanel/websocket-ruby'
gem 'websocket-native'
class ChatController < ActionController::Base
def index
socket = env['rack.hijack'].call
# Sending the header
handshake = WebSocket::Handshake::Server.new
handshake.from_rack env
socket.write handshake.to_s
# Reading a frame
buffer = WebSocket::Frame::Incoming::Server.new({
version: handshake.version})
raw_data = socket.recvfrom(2000).first
buffer << raw_data
while frame = buffer.next do
// handle frame.data
end
# Writing a frame
msg = "Hello"
frame = WebSocket::Frame::Outgoing::Server.new({
version: handshake.version, type: 'text', data: msg})
socket.write frame.to_s
end
end
ws = new WebSocket('ws://server:port/chat')
ws.onopen = function() {
// do something upon connection
};
ws.onmessage = function(event) {
// handle event.data
};
ws.send(data);
ws.onclose = function() {
// teardown
}
hijack do |tubesock|
tubesock.onopen do
tubesock.send_data message: "Hello, friend"
end
tubesock.onmessage do |data|
tubesock.send_data message: "You said: #{data[:message]}"
end
end