Module: Smith::Doctor::Checks::Durability

Defined in:
lib/smith/doctor/checks/durability.rb

Constant Summary collapse

PROBE_KEY =
"smith_doctor_probe"

Class Method Summary collapse

Class Method Details

.add_backend_warning(report, adapter) ⇒ Object



90
91
92
93
94
95
96
97
98
99
# File 'lib/smith/doctor/checks/durability.rb', line 90

def self.add_backend_warning(report, adapter)
  warning = adapter.respond_to?(:durability_warning) ? adapter.durability_warning : nil
  return unless warning

  report.add(
    name: "durability.backend",
    status: :warn,
    message: warning
  )
end

.build_probe_classObject



82
83
84
85
86
87
88
# File 'lib/smith/doctor/checks/durability.rb', line 82

def self.build_probe_class
  Class.new(::Smith::Workflow) do
    initial_state :idle
    state :done
    transition :finish, from: :idle, to: :done
  end
end

.check_persist_and_restore(report, adapter) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/smith/doctor/checks/durability.rb', line 38

def self.check_persist_and_restore(report, adapter)
  workflow_class = build_probe_class
  payload = JSON.generate(workflow_class.new.to_state)

  adapter.store(PROBE_KEY, payload)
  restored_payload = adapter.fetch(PROBE_KEY)
  restored = workflow_class.from_state(JSON.parse(restored_payload))
  adapter.delete(PROBE_KEY)

  valid = restored.state == :idle
  report.add(
    name: "durability.persist_restore",
    status: valid ? :pass : :fail,
    message: valid ? "Host persistence round-trip works" : "Host persistence round-trip failed"
  )
rescue StandardError => e
  report.add(
    name: "durability.persist_restore", status: :fail,
    message: "Host persistence round-trip failed", detail: e.message
  )
end

.check_resume_after_restore(report, adapter) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/smith/doctor/checks/durability.rb', line 60

def self.check_resume_after_restore(report, adapter)
  workflow_class = build_probe_class
  payload = JSON.generate(workflow_class.new.to_state)

  adapter.store(PROBE_KEY, payload)
  restored_payload = adapter.fetch(PROBE_KEY)
  restored = workflow_class.from_state(JSON.parse(restored_payload))
  adapter.delete(PROBE_KEY)

  result = restored.run!
  valid = result.state == :done

  report.add(
    name: "durability.resume_after_restore",
    status: valid ? :pass : :fail,
    message: valid ? "Restored workflow resumes correctly" : "Restored workflow did not reach terminal state"
  )
rescue StandardError => e
  report.add(name: "durability.resume_after_restore", status: :fail,
             message: "Resume after restore failed", detail: e.message)
end

.run(report) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/smith/doctor/checks/durability.rb', line 11

def self.run(report)
  raw_adapter = ::Smith.config.persistence_adapter
  unless raw_adapter
    report.add(
      name: "durability.adapter",
      status: :warn,
      message: "No persistence adapter configured",
      detail: "Set config.persistence_adapter to :rails_cache, :active_record, :redis, :cache_store, or a custom adapter"
    )
    return
  end

  adapter = ::Smith.persistence_adapter
  add_backend_warning(report, adapter)
rescue StandardError => e
  report.add(
    name: "durability.adapter",
    status: :fail,
    message: "Persistence adapter configuration is invalid",
    detail: e.message
  )
  return
else
  check_persist_and_restore(report, adapter)
  check_resume_after_restore(report, adapter)
end