Action Cable dan WebSockets di Rails: Panduan Lengkap untuk Wawancara Teknis

Panduan lengkap Action Cable dan WebSockets di Rails untuk persiapan wawancara teknis. Mencakup arsitektur, Solid Cable, Turbo Streams, dan pola scaling.

Action Cable dan WebSockets di Rails untuk wawancara teknis

Komunikasi real-time telah menjadi fitur yang sangat penting dalam aplikasi web modern. Mulai dari fitur chat, notifikasi langsung, hingga pembaruan dashboard secara otomatis, pengguna mengharapkan pengalaman yang responsif tanpa perlu memuat ulang halaman. Action Cable, yang merupakan framework bawaan Rails untuk WebSockets, menyediakan solusi terintegrasi yang memungkinkan pengembang membangun fitur-fitur tersebut dengan mengikuti konvensi Rails yang sudah familiar.

Poin Penting untuk Wawancara

Action Cable menjembatani komunikasi WebSocket dengan arsitektur Rails yang sudah ada, sehingga memungkinkan pengembangan fitur real-time menggunakan pola yang konsisten dengan bagian aplikasi Rails lainnya. Rails 8 memperkenalkan Solid Cable, adapter berbasis database yang mengeliminasi kebutuhan akan Redis untuk pub/sub messaging.

Dasar-Dasar Protokol WebSocket

Protokol WebSocket menyediakan saluran komunikasi full-duplex melalui koneksi TCP tunggal. Berbeda dengan model request-response tradisional HTTP, WebSocket mempertahankan koneksi persisten yang memungkinkan server dan klien untuk saling mengirim data kapan saja. Proses ini dimulai dengan HTTP handshake yang kemudian di-upgrade menjadi koneksi WebSocket.

Perbedaan mendasar antara HTTP dan WebSocket terletak pada sifat koneksinya. HTTP bersifat stateless dan unidirectional, di mana klien harus selalu menginisiasi request. Sebaliknya, WebSocket bersifat stateful dan bidirectional, memungkinkan komunikasi dua arah secara simultan. Karakteristik ini membuat WebSocket sangat cocok untuk aplikasi yang membutuhkan pembaruan data secara real-time.

Dalam konteks Rails, Action Cable mengabstraksi kompleksitas manajemen koneksi WebSocket, sehingga pengembang dapat fokus pada logika bisnis aplikasi tanpa harus menangani detail teknis protokol secara langsung.

Arsitektur Action Cable

Action Cable terdiri dari tiga komponen utama: connections, channels, dan subscriptions. Pemahaman mendalam tentang ketiga komponen ini sangat penting untuk membangun fitur real-time yang robust dan scalable.

Connections

Connection merepresentasikan koneksi WebSocket individual antara klien dan server. Setiap connection dapat diidentifikasi berdasarkan pengguna yang terautentikasi, memungkinkan pengiriman pesan yang ditargetkan kepada pengguna tertentu.

ruby
# app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      # Cookies are available in WebSocket handshake
      if verified_user = User.find_by(id: cookies.encrypted[:user_id])
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

Kode di atas mendemonstrasikan bagaimana autentikasi ditangani pada level connection. Method find_verified_user mengakses cookies yang tersedia selama WebSocket handshake untuk memverifikasi identitas pengguna. Jika pengguna tidak terautentikasi, koneksi akan ditolak dengan reject_unauthorized_connection.

Channels

Channel berfungsi sebagai unit logis untuk mengorganisasi fitur real-time. Setiap channel menangani jenis komunikasi tertentu, seperti chat, notifikasi, atau pembaruan dashboard. Pendekatan ini mengikuti prinsip separation of concerns yang menjadi fondasi arsitektur Rails.

ruby
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    room = ChatRoom.find(params[:room_id])
    # Authorization: verify user belongs to this room
    if room.members.include?(current_user)
      stream_for room
    else
      reject
    end
  end

  def receive(data)
    message = ChatMessage.create!(
      room_id: params[:room_id],
      user: current_user,
      body: data["body"]
    )
    ChatChannel.broadcast_to(
      message.room,
      { id: message.id, body: message.body, user: current_user.name }
    )
  end

  def unsubscribed
    # Cleanup: mark user as offline
    AppearanceTracker.mark_offline(current_user)
  end
end

Implementasi ChatChannel di atas menunjukkan beberapa konsep penting. Method subscribed menangani otorisasi dengan memverifikasi bahwa pengguna merupakan anggota chat room. Method receive memproses pesan masuk dari klien dan melakukan broadcast ke semua subscriber. Method unsubscribed menjalankan cleanup logic ketika koneksi terputus.

Penggunaan stream_for dengan model object memungkinkan Action Cable untuk secara otomatis mengelola nama stream berdasarkan class dan ID model. Pola ini menyederhanakan manajemen stream dan mengurangi kemungkinan kesalahan dalam penamaan.

Subscriptions di Sisi Klien

Integrasi sisi klien menggunakan JavaScript untuk membuat dan mengelola subscriptions ke channels. Rails menyediakan consumer object yang menangani koneksi WebSocket dan menyediakan API untuk berinteraksi dengan server.

app/javascript/channels/chat_channel.jsjavascript
import consumer from "./consumer"

const chatChannel = consumer.subscriptions.create(
  { channel: "ChatChannel", room_id: roomId },
  {
    connected() {
      // Called when the subscription is ready
      console.log("Connected to chat room", roomId)
    },

    disconnected() {
      // Called when the subscription is closed
      console.log("Disconnected from chat room")
    },

    received(data) {
      // Called when data is broadcast to the channel
      const messageList = document.getElementById("messages")
      messageList.insertAdjacentHTML("beforeend",
        `<div class="message"><strong>${data.user}</strong>: ${data.body}</div>`
      )
    },

    sendMessage(body) {
      // Calls ChatChannel#receive on the server
      this.perform("receive", { body: body })
    }
  }
)

Kode JavaScript di atas mendemonstrasikan lifecycle lengkap subscription. Callback connected dipanggil ketika subscription berhasil dibuat, disconnected ketika koneksi terputus, dan received ketika data diterima dari server. Method sendMessage menunjukkan bagaimana klien dapat mengirim data ke server menggunakan this.perform.

Pola ini memisahkan concerns dengan jelas: server menangani logika bisnis dan persistensi data, sementara klien menangani rendering dan interaksi pengguna.

Siap menguasai wawancara Ruby on Rails Anda?

Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.

Solid Cable di Rails 8

Rails 8 memperkenalkan Solid Cable sebagai adapter default untuk Action Cable. Solid Cable menyimpan messages di database relasional menggunakan polling yang dioptimalkan, mengeliminasi kebutuhan akan Redis untuk banyak kasus penggunaan. Pendekatan ini menyederhanakan infrastruktur deployment tanpa mengorbankan performa secara signifikan untuk aplikasi skala kecil hingga menengah.

yaml
# config/cable.yml (Rails 8 default)
development:
  adapter: solid_cable

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

Konfigurasi di atas menunjukkan setup Solid Cable untuk development dan production. Perhatikan penggunaan connects_to yang memungkinkan Solid Cable menggunakan database terpisah untuk operasi cable, mencegah interferensi dengan database utama aplikasi.

ruby
# config/database.yml (Rails 8 multi-database)
production:
  primary:
    <<: *default
    database: myapp_production
  cable:
    <<: *default
    database: myapp_cable_production
    migrations_paths: db/cable_migrate

Konfigurasi multi-database ini memisahkan storage untuk cable messages dari database utama. Pemisahan ini memberikan beberapa keuntungan: mengurangi beban pada database utama, memungkinkan scaling independen, dan menyederhanakan manajemen retensi data untuk messages yang bersifat ephemeral.

Solid Cable cocok untuk aplikasi dengan ratusan hingga ribuan koneksi simultan. Untuk aplikasi dengan skala yang lebih besar, Redis tetap menjadi pilihan yang direkomendasikan karena karakteristik performa yang lebih superior untuk operasi pub/sub.

Pola Broadcasting

Broadcasting merupakan mekanisme untuk mengirim data dari server ke semua subscribers yang relevan. Rails menyediakan beberapa pola untuk melakukan broadcast, masing-masing dengan trade-offs tersendiri.

ruby
# Broadcasting from a model callback
class Notification < ApplicationRecord
  belongs_to :user
  after_create_commit :broadcast_to_user

  private

  def broadcast_to_user
    ActionCable.server.broadcast(
      "notifications_#{user_id}",
      { id: id, title: title, read: false }
    )
  end
end

# Broadcasting from a background job
class DashboardUpdateJob < ApplicationJob
  queue_as :default

  def perform(dashboard_id)
    dashboard = Dashboard.find(dashboard_id)
    stats = dashboard.compute_stats
    ActionCable.server.broadcast(
      "dashboard_#{dashboard_id}",
      { stats: stats, updated_at: Time.current.iso8601 }
    )
  end
end

Kedua pola di atas mendemonstrasikan pendekatan yang berbeda untuk broadcasting. Model callback cocok untuk broadcast yang langsung terkait dengan perubahan data, memastikan konsistensi antara state database dan notifikasi real-time. Background job lebih tepat untuk operasi yang membutuhkan komputasi intensif atau tidak perlu blocking.

Penggunaan after_create_commit alih-alih after_create sangat penting untuk memastikan bahwa broadcast hanya terjadi setelah transaksi database berhasil di-commit. Pola ini mencegah race condition di mana klien menerima notifikasi tentang data yang belum tersedia di database.

Integrasi Turbo Streams

Turbo Streams, bagian dari Hotwire, menyediakan abstraksi tingkat tinggi untuk broadcasting DOM updates. Integrasi ini memungkinkan pengembang untuk membangun fitur real-time dengan kode minimal, mengikuti prinsip convention over configuration.

ruby
# app/models/message.rb
class Message < ApplicationRecord
  belongs_to :chat_room
  # Automatically broadcasts append to subscribers
  broadcasts_to :chat_room
end

# app/views/chat_rooms/show.html.erb
<%= turbo_stream_from @chat_room %>
<div id="messages">
  <%= render @chat_room.messages %>
</div>

Dengan broadcasts_to, Rails secara otomatis melakukan broadcast Turbo Stream frames ketika model dibuat, diupdate, atau dihapus. Helper turbo_stream_from di view membuat subscription ke channel yang sesuai dan menangani rendering updates secara otomatis.

Pendekatan deklaratif ini secara signifikan mengurangi boilerplate code. Pengembang tidak perlu menulis JavaScript untuk handling DOM updates atau mendefinisikan channel classes untuk kasus penggunaan standar. Namun, untuk kebutuhan yang lebih kompleks, pendekatan manual tetap tersedia dan dapat dikombinasikan dengan Turbo Streams.

Scaling di Production

Untuk aplikasi dengan traffic tinggi, arsitektur Action Cable perlu dipertimbangkan dengan cermat. Setiap koneksi WebSocket mempertahankan state di server, yang berbeda dari model stateless HTTP tradisional.

ruby
# config/cable.yml — Redis adapter for high-scale production
production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
  channel_prefix: myapp_production

Redis adapter merupakan pilihan standar untuk production deployment dengan skala besar. Redis menyediakan pub/sub yang efisien dengan latency rendah, memungkinkan multiple Rails processes atau servers untuk berbagi channel subscriptions.

Beberapa pertimbangan penting untuk scaling Action Cable meliputi pengelolaan connection pooling, implementasi health checks untuk WebSocket connections, dan strategi reconnection yang robust di sisi klien. Penggunaan load balancer yang mendukung WebSocket connections juga merupakan keharusan, dengan sticky sessions sebagai pendekatan yang umum digunakan.

Monitoring merupakan aspek kritis dalam production deployment. Metrik seperti jumlah koneksi aktif, message throughput, dan latency perlu dipantau untuk mengidentifikasi bottlenecks dan merencanakan capacity planning.

Wawasan Wawancara

Dalam wawancara teknis, pemahaman tentang trade-offs antara Solid Cable dan Redis, serta kemampuan untuk menjelaskan strategi scaling, menunjukkan pengetahuan yang mendalam tentang sistem production.

Testing Channels

Rails menyediakan testing framework yang komprehensif untuk Action Cable channels. Testing memastikan bahwa authorization logic, broadcast behavior, dan subscription lifecycle berfungsi sesuai ekspektasi.

ruby
# test/channels/chat_channel_test.rb
require "test_helper"

class ChatChannelTest < ActionCable::Channel::TestCase
  test "subscribes to a valid room" do
    room = chat_rooms(:general)
    user = users(:alice)
    stub_connection current_user: user

    subscribe room_id: room.id

    assert subscription.confirmed?
    assert_has_stream_for room
  end

  test "rejects subscription for unauthorized user" do
    room = chat_rooms(:private)
    user = users(:outsider)
    stub_connection current_user: user

    subscribe room_id: room.id

    assert subscription.rejected?
  end

  test "broadcasts messages to room subscribers" do
    room = chat_rooms(:general)
    stub_connection current_user: users(:alice)
    subscribe room_id: room.id

    assert_broadcast_on(room, hash_including(body: "Hello")) do
      perform :receive, body: "Hello"
    end
  end
end

Test cases di atas mencakup tiga skenario penting: subscription yang valid, rejection untuk unauthorized user, dan verifikasi broadcast behavior. Helper stub_connection memungkinkan setup connection state tanpa actual WebSocket connection. Assertion seperti assert_has_stream_for dan assert_broadcast_on menyediakan cara ekspresif untuk memverifikasi behavior.

Testing channel behavior secara terpisah dari integration tests memungkinkan feedback loop yang lebih cepat selama development dan membantu mengidentifikasi regressions dengan lebih presisi.

Pertanyaan Wawancara Umum

Beberapa pertanyaan yang sering muncul dalam wawancara teknis terkait Action Cable dan WebSockets meliputi penjelasan perbedaan antara HTTP polling, long polling, Server-Sent Events, dan WebSockets. Kandidat diharapkan dapat menjelaskan bagaimana Action Cable menangani autentikasi dan otorisasi pada koneksi WebSocket, serta mendeskripsikan arsitektur internal Action Cable termasuk connections, channels, dan subscriptions.

Bagaimana Action Cable mengautentikasi koneksi? Autentikasi terjadi di ApplicationCable::Connection#connect selama WebSocket handshake. Cookies dari HTTP session tersedia pada tahap ini. Autentikasi berbasis token dapat dilakukan dengan mengirim token sebagai query parameter pada URL WebSocket.

Apa yang terjadi ketika koneksi WebSocket terputus? Library klien Action Cable mengimplementasikan reconnection otomatis dengan exponential backoff. Di sisi server, callback unsubscribed dipanggil untuk setiap channel yang disubscribe oleh koneksi tersebut.

Kapan sebaiknya menggunakan Solid Cable dibanding Redis? Solid Cable cocok untuk aplikasi dengan kebutuhan real-time moderat (di bawah 100 pesan per detik) yang ingin menghindari infrastruktur Redis tambahan. Redis tetap diperlukan untuk skenario high-throughput atau ketika latency di bawah 10ms menjadi keharusan.

Kesalahan Umum

Menempatkan logika otorisasi di connection class alih-alih di channel individual merupakan kesalahan umum. Connection menangani autentikasi identitas (siapa pengguna ini?). Channel menangani otorisasi akses (apakah pengguna ini berhak mengakses room ini?). Mencampurkan tanggung jawab ini dapat menimbulkan celah keamanan.

Kesimpulan

  • WebSocket menyediakan komunikasi full-duplex yang berbeda dari model request-response HTTP tradisional
  • Action Cable terdiri dari tiga komponen utama: connections untuk autentikasi, channels untuk logika bisnis, dan subscriptions untuk manajemen client-side
  • Rails 8 memperkenalkan Solid Cable sebagai alternatif Redis yang lebih sederhana untuk deployment skala kecil hingga menengah
  • Turbo Streams menyediakan abstraksi deklaratif untuk broadcasting DOM updates dengan boilerplate minimal
  • Testing channel behavior secara terpisah memungkinkan verifikasi authorization dan broadcast logic yang lebih presisi
  • Scaling membutuhkan pertimbangan tentang adapter choice, connection management, dan monitoring
  • Latih pertanyaan wawancara Action Cable & WebSockets untuk memperkuat pemahaman konsep-konsep ini

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Tag

#action-cable
#websockets
#rails
#real-time
#solid-cable

Bagikan

Artikel terkait