Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ Rails Action Cable ด้วย Solid Cable: สร้าง Real-time Apps โดยไม่ต้องใช้ Redis

ทำไมต้องใช้ Rails Action Cable?

Modern web apps ต้องการ push updates ไป client real-time: chat messages, live notifications, collaborative apps, live tickers

Action Cable = built-in WebSocket library ของ Rails เปิด two-way persistent communication ระหว่าง server และ client Server ส่งข้อมูลไป browser ได้โดยไม่ต้องรอ request (no user-prompted refresh)

Action Cable บูรณาการ WebSockets เข้า Rails app ทำให้ real-time features ที่ยากใน server-rendered apps กลายเป็นได้ง่าย

Client side: Rails ให้ JavaScript consumer subscribe channels และรับ broadcasts Developer: define backend channels (คล้าย controllers แต่สำหรับ real-time streams)

Solid Cable คืออะไร?

Action Cable เก่าๆ production ต้องใช้ Redis (หรือ PostgreSQL NOTIFY) สำหรับ broadcast messages ข้าม server processes Pub/sub service (Redis) รับผิดชอบส่ง message จาก process หนึ่งไปทุก process เพื่อ forward ให้ WebSocket clients

Solid Cable (Rails 8) = database-backed adapter แทน Redis ใช้ existing database เป็น backend เหมือน Solid Queue (Active Job) และ Solid Cache (Active Cache)

WebSocket message เข้า -> เขียนลง database table -> ทุก Action Cable instances poll table นั้นหา messages ใหม่ broadcast ให้ clients (default: ทุก 100ms) ใกล้ real-time Messages เก็บไว้แค่ระยะสั้น (24 hours default) แล้ว prune -> debug ได้ ไม่วิตกพื้นที่ database

Solid Cable = ส่วนสุดท้ายของ "Solid Trifecta": caching, background jobs, real-time messaging ทั้งหมดผ่าน database

สร้าง Rails 8 app กับ Solid Cable

สร้าง example app

rails _8.1.0_ new solid_cable_chat --database=sqlite3
cd solid_cable_chat

Rails 8 มี Solid Cable built-in ไม่ต้อง add gems

Configure Solid Cable

bin/rails solid_cable:install

Generator สร้าง config/cable.yml (set Solid Cable adapter) และ db/cable_schema.rb (schema สำหรับ messages table)

Setup Database สำหรับ Solid Cable

Default: ใช้ separate database สำหรับ Solid Cable แยกจาก app data Development: ใช้ same DB หรือ separate DB ได้ นี่ใช้ separate SQLite database

Edit config/database.yml เพิ่ม cable database ใน development:

development:
  primary: <<: *default
    database: storage/development.sqlite3
  cable: <<: *default
    database: storage/development_cable.sqlite3
    migrations_paths: db/cable_migrate

Edit config/cable.yml ใช้ solid_cable adapter ใน development:

development:
  adapter: solid_cable
  connects_to:
    database:
      writing: cable
  polling_interval: 0.1.seconds
  message_retention: 1.day

รัน rails db:prepare

Setup Action Cable Channel

Channels = Ruby classes handle data streams (คล้าย controllers สำหรับ HTTP)

rails generate channel UserChat

Edit app/channels/user_chat_channel.rb:

class UserChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "user_chat_channel"
  end
  def unsubscribed; end
  def talk(data)
    message = data["content"]
    ActionCable.server.broadcast("user_chat_channel", { content: message })
  end
end

subscribed: stream_from "user_chat_channel" ทุกคน subscribed channel นี้จะได้รับ broadcasts

talk: custom action เรียกจาก client ด้วย perform("talk", { content: "..." }) broadcast ไปทุก subscriber

Build Consumer ใน Client

Edit app/javascript/channels/user_chat_channel.js:

import consumer from "channels/consumer";
const userChatChannel = consumer.subscriptions.create("UserChatChannel", {
  connected() { console.log("Connected"); },
  disconnected() { console.log("Disconnected"); },
  received(data) {
    const messagesDiv = document.getElementById("messages");
    if (messagesDiv && data.content) {
      const messageElement = document.createElement("p");
      messageElement.textContent = data.content;
      messagesDiv.appendChild(messageElement);
    }
  }
});
function sendMessage(content) {
  userChatChannel.perform("talk", { content: content });
}
export { sendMessage };
window.sendMessage = sendMessage;

received(data) callback สำคัญ - เรียกเมื่อได้ broadcast จาก server update chat log real-time

Build Simple UI

rails generate controller UserChat index

View: form ส่งข้อความ + div แสดง messages

root "user_chat#index"

ทดสอบ Real-time

bin/dev -> localhost:3000 เปิด 2 tabs ส่งข้อความจาก tab หนึ่ง -> ปรากฏในอีก tab ทันที

Deploy Rails Action Cable Production

Solid Cable ใช้ database table Rails 8 default SQLite สำหรับ Solid Cable ใน new apps แต่ point ไป database ไหนก็ได้โดยเพิ่ม cable section ใน database.yml

แนะนำ: ใช้ separate database สำหรับ Solid Cable ใน production แยก real-time messaging load จาก app data หลัก (เช่น app_production_cable แยกจาก app_production)

จำ: run rails db:prepare หรือ rails db:migrate ใน production สร้าง messages table

แต่ละ WebSocket connection ใช้ server memory ต้องมี resources พอ

Configure Polling Intervals

Polling frequency configurable: ลด interval = poll บ่อยขึ้น = latency ต่ำ แต่ SELECT queries มากขึ้น เพิ่ม interval = database load น้อย แต่ delay มากขึ้น Default 0.1s (10 polls/sec) = จุดเริ่มต้นดี

Solid Cable: ปilarenสำคัญของ Solid Trifecta

Solid Cache (caching without Redis) + Solid Queue (background jobs without Redis) + Solid Cable (WebSockets without Redis) = ระบบ interactive apps ครบครัน infrastructure น้อยที่สุด

ข้อได้เปรียบ: ใช้งานได้ทันที deployment 簡單 (ไม่ต้อง Redis) performance พอสำหรับหลาย apps

Monitor production ด้วย Honeybadger สำหรับ error และ performance monitoring