Class: Upkeep::Rails::ClusterGuard

Inherits:
Object
  • Object
show all
Defined in:
lib/upkeep/rails/cluster_guard.rb

Overview

Detects boot configurations where live updates silently break across cluster workers: an in-process cable adapter or an in-memory subscription store cannot reach browsers or subscriptions held by another process.

Constant Summary collapse

IN_PROCESS_CABLE_ADAPTERS =
%w[async].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cable_adapter:, worker_count:, subscription_store:, environment:) ⇒ ClusterGuard

Returns a new instance of ClusterGuard.



14
15
16
17
18
19
# File 'lib/upkeep/rails/cluster_guard.rb', line 14

def initialize(cable_adapter:, worker_count:, subscription_store:, environment:)
  @cable_adapter = cable_adapter.to_s
  @worker_count = worker_count.to_i
  @subscription_store = subscription_store&.to_sym
  @environment = environment.to_s
end

Instance Attribute Details

#cable_adapterObject (readonly)

Returns the value of attribute cable_adapter.



12
13
14
# File 'lib/upkeep/rails/cluster_guard.rb', line 12

def cable_adapter
  @cable_adapter
end

#environmentObject (readonly)

Returns the value of attribute environment.



12
13
14
# File 'lib/upkeep/rails/cluster_guard.rb', line 12

def environment
  @environment
end

#subscription_storeObject (readonly)

Returns the value of attribute subscription_store.



12
13
14
# File 'lib/upkeep/rails/cluster_guard.rb', line 12

def subscription_store
  @subscription_store
end

#worker_countObject (readonly)

Returns the value of attribute worker_count.



12
13
14
# File 'lib/upkeep/rails/cluster_guard.rb', line 12

def worker_count
  @worker_count
end

Instance Method Details

#clustered?Boolean

Returns:

  • (Boolean)


21
22
23
# File 'lib/upkeep/rails/cluster_guard.rb', line 21

def clustered?
  worker_count.positive?
end

#error?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/upkeep/rails/cluster_guard.rb', line 41

def error?
  problems.any? && environment == "production"
end

#messageObject



49
50
51
52
53
54
# File 'lib/upkeep/rails/cluster_guard.rb', line 49

def message
  return if problems.empty?

  "Upkeep detected a clustered server (#{worker_count} workers) with a configuration that cannot " \
    "deliver live updates across processes: #{problems.join("; ")}."
end

#problemsObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/upkeep/rails/cluster_guard.rb', line 25

def problems
  return [] unless clustered?

  problems = []
  if IN_PROCESS_CABLE_ADAPTERS.include?(cable_adapter)
    problems << "the #{cable_adapter} Action Cable adapter is in-process, so broadcasts from one worker " \
      "never reach sockets held by another; configure a cross-process cable adapter such as solid_cable " \
      "or redis in config/cable.yml"
  end
  if subscription_store == :memory
    problems << "subscription_store=:memory is per-process, so subscriptions registered in one worker are " \
      "invisible to the others; set config.upkeep.subscription_store = :active_record"
  end
  problems
end

#warning?Boolean

Returns:

  • (Boolean)


45
46
47
# File 'lib/upkeep/rails/cluster_guard.rb', line 45

def warning?
  problems.any? && !error?
end