or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

connection-management.mdindex.mdjavascript-client.mdrails-integration.mdserver-broadcasting.mdsubscription-adapters.md
tile.json

subscription-adapters.mddocs/

Subscription Adapters

Subscription adapters provide pluggable pub/sub backends for scaling ActionCable across multiple server processes and machines. ActionCable ships with several built-in adapters for different deployment scenarios.

Capabilities

Base Adapter Interface

Abstract base class defining the interface all subscription adapters must implement.

class ActionCable::SubscriptionAdapter::Base
  def initialize(server)
  end
  
  # Broadcast message to a channel
  # @param channel [String] Channel name to broadcast to
  # @param payload [String] JSON-encoded message payload
  def broadcast(channel, payload)
    raise NotImplementedError
  end
  
  # Subscribe to a channel
  # @param channel [String] Channel name to subscribe to  
  # @param message_callback [Proc] Callback for received messages
  # @param success_callback [Proc] Optional success callback
  def subscribe(channel, message_callback, success_callback = nil)
    raise NotImplementedError
  end
  
  # Unsubscribe from a channel
  # @param channel [String] Channel name to unsubscribe from
  # @param message_callback [Proc] Message callback to remove
  def unsubscribe(channel, message_callback)
    raise NotImplementedError
  end
  
  # Shutdown the adapter and cleanup resources
  def shutdown
    raise NotImplementedError
  end
  
  attr_reader :logger, :server
end

Redis Adapter

Production-ready adapter using Redis for pub/sub across multiple servers.

class ActionCable::SubscriptionAdapter::Redis < ActionCable::SubscriptionAdapter::Base
  def initialize(server)
    super
  end
  
  # Broadcast message via Redis PUBLISH
  def broadcast(channel, payload)
  end
  
  # Subscribe to Redis channel
  def subscribe(channel, message_callback, success_callback = nil)
  end
  
  # Unsubscribe from Redis channel  
  def unsubscribe(channel, message_callback)
  end
  
  # Shutdown Redis connections
  def shutdown
  end
end

Configuration Example:

# config/cable.yml
production:
  adapter: redis
  url: redis://localhost:6379/1
  channel_prefix: myapp_production

# Or with Redis connection options
production:
  adapter: redis
  url: redis://user:password@redis.example.com:6380/0
  channel_prefix: myapp_production
  timeout: 1

PostgreSQL Adapter

Database-backed adapter using PostgreSQL's LISTEN/NOTIFY for pub/sub.

class ActionCable::SubscriptionAdapter::PostgreSQL < ActionCable::SubscriptionAdapter::Base
  def initialize(server)
    super
  end
  
  # Broadcast via PostgreSQL NOTIFY
  def broadcast(channel, payload)
  end
  
  # Subscribe via PostgreSQL LISTEN
  def subscribe(channel, message_callback, success_callback = nil)
  end
  
  # Unsubscribe via PostgreSQL UNLISTEN
  def unsubscribe(channel, message_callback)
  end
  
  # Shutdown PostgreSQL connections
  def shutdown
  end
end

Configuration Example:

# config/cable.yml  
production:
  adapter: postgresql
  url: postgresql://user:password@localhost/myapp_production
  channel_prefix: myapp_production

Async Adapter

In-memory adapter using concurrent-ruby for single-server deployments.

class ActionCable::SubscriptionAdapter::Async < ActionCable::SubscriptionAdapter::Base
  def initialize(server)
    super
  end
  
  # Broadcast to in-memory subscribers
  def broadcast(channel, payload)
  end
  
  # Subscribe to in-memory channel
  def subscribe(channel, message_callback, success_callback = nil)
  end
  
  # Unsubscribe from in-memory channel
  def unsubscribe(channel, message_callback)
  end
  
  # Shutdown async executor
  def shutdown
  end
end

Configuration Example:

# config/cable.yml
development:
  adapter: async

test:
  adapter: test

Inline Adapter

Synchronous adapter for testing - executes callbacks immediately.

class ActionCable::SubscriptionAdapter::Inline < ActionCable::SubscriptionAdapter::Base
  def initialize(server)
    super
  end
  
  # Broadcast immediately to subscribers
  def broadcast(channel, payload)
  end
  
  # Subscribe immediately
  def subscribe(channel, message_callback, success_callback = nil)
  end
  
  # Unsubscribe immediately
  def unsubscribe(channel, message_callback)
  end
  
  # No-op shutdown
  def shutdown
  end
end

Adapter Helper Modules

Channel Prefix

Adds channel prefixing capabilities to adapters.

module ActionCable::SubscriptionAdapter::ChannelPrefix
  private
  
  # Add configured prefix to channel name
  # @param channel [String] Base channel name
  # @return [String] Prefixed channel name
  def channel_with_prefix(channel)
  end
  
  # Get channel prefix from configuration
  # @return [String] Configured channel prefix
  def channel_prefix
  end
end

Subscriber Map

Manages subscription mappings for adapters.

class ActionCable::SubscriptionAdapter::SubscriberMap
  def initialize
  end
  
  # Add subscription
  # @param channel [String] Channel name
  # @param callback [Proc] Message callback
  def add_subscription(channel, callback)
  end
  
  # Remove subscription
  # @param channel [String] Channel name  
  # @param callback [Proc] Message callback to remove
  def remove_subscription(channel, callback)
  end
  
  # Get callbacks for channel
  # @param channel [String] Channel name
  # @return [Array<Proc>] Array of callbacks
  def broadcast(channel, message)
  end
  
  # Remove all subscriptions for channel
  # @param channel [String] Channel name
  def remove_channel(channel)
  end
end

Adapter Configuration

Server Configuration

Accessing and configuring the subscription adapter.

class ActionCable::Server::Base
  # Get the configured pubsub adapter instance
  def pubsub
    @pubsub ||= config.pubsub_adapter.new(self)
  end
  
  attr_reader :config
end

class ActionCable::Server::Configuration
  # Subscription adapter class (defaults to Async)
  attr_accessor :pubsub_adapter
  
  # Adapter-specific configuration
  attr_accessor :cable
end

Usage Examples:

# Get current adapter
adapter = ActionCable.server.pubsub
# => #<ActionCable::SubscriptionAdapter::Redis:0x...>

# Access configuration
config = ActionCable.server.config
puts config.cable[:adapter]
# => "redis"

# Manual adapter configuration
ActionCable.server.config.pubsub_adapter = ActionCable::SubscriptionAdapter::PostgreSQL

Adapter Selection

ActionCable automatically selects adapters based on configuration:

# config/cable.yml determines adapter
development:
  adapter: async          # Uses Async adapter

test:  
  adapter: test          # Uses Inline adapter
  
production:
  adapter: redis         # Uses Redis adapter
  url: redis://localhost:6379/1

Custom Adapters

Creating custom subscription adapters:

class CustomAdapter < ActionCable::SubscriptionAdapter::Base
  def broadcast(channel, payload)
    # Custom broadcasting logic
  end
  
  def subscribe(channel, message_callback, success_callback = nil)
    # Custom subscription logic  
  end
  
  def unsubscribe(channel, message_callback)
    # Custom unsubscription logic
  end
  
  def shutdown
    # Custom cleanup logic
  end
end

# Configure custom adapter
ActionCable.server.config.pubsub_adapter = CustomAdapter

Adapter Performance Considerations

Redis Adapter

  • Best for: Multi-server production deployments
  • Pros: High performance, battle-tested, supports persistence
  • Cons: Requires Redis server, additional infrastructure
  • Scaling: Excellent horizontal scaling capabilities

PostgreSQL Adapter

  • Best for: Applications already using PostgreSQL
  • Pros: No additional infrastructure, transactional guarantees
  • Cons: Database connection overhead, limited throughput vs Redis
  • Scaling: Good for moderate loads

Async Adapter

  • Best for: Development and single-server deployments
  • Pros: No external dependencies, fast for single server
  • Cons: No cross-server communication, memory usage grows with connections
  • Scaling: Single server only

Inline Adapter

  • Best for: Testing only
  • Pros: Immediate execution, deterministic behavior
  • Cons: Synchronous execution can block, not for production
  • Scaling: Not applicable