aboutsummaryrefslogblamecommitdiffstats
path: root/actioncable/lib/action_cable/server/base.rb
blob: b1a0e116312f73ba547765f3ee4be80452cdc253 (plain) (tree)
1
2
3
4
5
6
7
8
9
                 
 

                  

                                                                                                                                                          
     
                                                                                                     
              
                                               
                                              
 
                                                                                                 
 

                                         
 

                        
                    

                                                                                           

         
                                           
                   
                             
                                                      

         
                                                                                                                      



                                                        









                                          

                                                                 
                                                                                                         

         

                                                                                         

         










                                                                                                                                                
                     
                                                                                                                                  

         
                                                                                                   
                         




                                                                                                          


           
                                                  
                
                                                                                     

         
                                                                                           
                                
                                           

         

                                                            
     
   
require 'monitor'

module ActionCable
  module Server
    # A singleton ActionCable::Server instance is available via ActionCable.server. It's used by the Rack process that starts the Action Cable server, but
    # is also used by the user to reach the RemoteConnections object, which is used for finding and disconnecting connections across all servers.
    #
    # Also, this is the server instance used for broadcasting. See Broadcasting for more information.
    class Base
      include ActionCable::Server::Broadcasting
      include ActionCable::Server::Connections

      cattr_accessor(:config, instance_accessor: true) { ActionCable::Server::Configuration.new }

      def self.logger; config.logger; end
      delegate :logger, to: :config

      attr_reader :mutex

      def initialize
        @mutex = Monitor.new
        @remote_connections = @event_loop = @worker_pool = @channel_classes = @pubsub = nil
      end

      # Called by Rack to setup the server.
      def call(env)
        setup_heartbeat_timer
        config.connection_class.new(self, env).process
      end

      # Disconnect all the connections identified by `identifiers` on this server or any others via RemoteConnections.
      def disconnect(identifiers)
        remote_connections.where(identifiers).disconnect
      end

      def restart
        connections.each(&:close)

        @mutex.synchronize do
          worker_pool.halt if @worker_pool

          @worker_pool = nil
        end
      end

      # Gateway to RemoteConnections. See that class for details.
      def remote_connections
        @remote_connections || @mutex.synchronize { @remote_connections ||= RemoteConnections.new(self) }
      end

      def event_loop
        @event_loop || @mutex.synchronize { @event_loop ||= config.event_loop_class.new }
      end

      # The worker pool is where we run connection callbacks and channel actions. We do as little as possible on the server's main thread.
      # The worker pool is an executor service that's backed by a pool of threads working from a task queue. The thread pool size maxes out
      # at 4 worker threads by default. Tune the size yourself with config.action_cable.worker_pool_size.
      #
      # Using Active Record, Redis, etc within your channel actions means you'll get a separate connection from each thread in the worker pool.
      # Plan your deployment accordingly: 5 servers each running 5 Puma workers each running an 8-thread worker pool means at least 200 database
      # connections.
      #
      # Also, ensure that your database connection pool size is as least as large as your worker pool size. Otherwise, workers may oversubscribe
      # the db connection pool and block while they wait for other workers to release their connections. Use a smaller worker pool or a larger
      # db connection pool instead.
      def worker_pool
        @worker_pool || @mutex.synchronize { @worker_pool ||= ActionCable::Server::Worker.new(max_size: config.worker_pool_size) }
      end

      # Requires and returns a hash of all of the channel class constants, which are keyed by name.
      def channel_classes
        @channel_classes || @mutex.synchronize do
          @channel_classes ||= begin
            config.channel_paths.each { |channel_path| require channel_path }
            config.channel_class_names.each_with_object({}) { |name, hash| hash[name] = name.constantize }
          end
        end
      end

      # Adapter used for all streams/broadcasting.
      def pubsub
        @pubsub || @mutex.synchronize { @pubsub ||= config.pubsub_adapter.new(self) }
      end

      # All of the identifiers applied to the connection class associated with this server.
      def connection_identifiers
        config.connection_class.identifiers
      end
    end

    ActiveSupport.run_load_hooks(:action_cable, Base.config)
  end
end