diff --git a/lib/action_cable/subscription_adapter/solid_cable.rb b/lib/action_cable/subscription_adapter/solid_cable.rb index 4c5ac55..97834fe 100644 --- a/lib/action_cable/subscription_adapter/solid_cable.rb +++ b/lib/action_cable/subscription_adapter/solid_cable.rb @@ -39,6 +39,7 @@ def listener end class Listener < ::ActionCable::SubscriptionAdapter::SubscriberMap + CONNECTION_ERRORS = [ActiveRecord::ConnectionFailed] Stop = Class.new(Exception) def initialize(event_loop) @@ -51,11 +52,17 @@ def initialize(event_loop) # for specific sections of code, rather than acquired. @critical = Concurrent::Semaphore.new(0) + @reconnect_attempt = 0 + @thread = Thread.new do Thread.current.name = "solid_cable_listener" Thread.current.report_on_exception = true - listen + begin + listen + rescue *CONNECTION_ERRORS + retry if retry_connecting? + end end end @@ -107,6 +114,7 @@ def invoke_callback(*) private attr_reader :event_loop, :thread attr_writer :last_id + attr_accessor :reconnect_attempt def last_id @last_id ||= last_message_id @@ -146,6 +154,22 @@ def with_polling_volume yield end end + + def reconnect_attempts + @reconnect_attempts ||= ::SolidCable.reconnect_attempts + end + + def retry_connecting? + self.reconnect_attempt += 1 + + return false if reconnect_attempt > reconnect_attempts.size + + sleep_t = reconnect_attempts[reconnect_attempt - 1] + + sleep(sleep_t) if sleep_t > 0 + + true + end end end end diff --git a/lib/solid_cable.rb b/lib/solid_cable.rb index 5ca850e..9eb9cf7 100644 --- a/lib/solid_cable.rb +++ b/lib/solid_cable.rb @@ -48,6 +48,12 @@ def trim_chance 2 end + def reconnect_attempts + attempts = cable_config.fetch(:reconnect_attempts, 1) + attempts = Array.new(attempts, 0) if attempts.is_a?(Integer) + attempts + end + private def cable_config Rails.application.config_for("cable")