Module: Textus::Doctor
- Defined in:
- lib/textus/doctor.rb,
lib/textus/doctor/check.rb,
lib/textus/doctor/check/hooks.rb,
lib/textus/doctor/check/schemas.rb,
lib/textus/doctor/check/audit_log.rb,
lib/textus/doctor/check/sentinels.rb,
lib/textus/doctor/check/templates.rb,
lib/textus/doctor/check/illegal_keys.rb,
lib/textus/doctor/check/manifest_files.rb,
lib/textus/doctor/check/schema_violations.rb,
lib/textus/doctor/check/unowned_schema_fields.rb
Overview
Health check for a Textus store. Returns a JSON-friendly Hash envelope with an ‘issues` array and a summary. Each issue is a Hash with `code`, `level`, `subject`, `message`, and optionally `fix`.
Defined Under Namespace
Classes: Check
Constant Summary collapse
- LEVELS =
%w[error warning info].freeze
- DOCTOR_CHECK_TIMEOUT_SECONDS =
2- CHECKS =
[ Check::ManifestFiles, Check::Schemas, Check::Templates, Check::Hooks, Check::IllegalKeys, Check::Sentinels, Check::AuditLog, Check::UnownedSchemaFields, Check::SchemaViolations, ].freeze
- ALL_CHECKS =
CHECKS.map(&:name_key).freeze
Class Method Summary collapse
- .fail_issue(name, code:, message:, fix:) ⇒ Object
- .run(store, checks: nil) ⇒ Object
- .run_registered_checks(store) ⇒ Object
Class Method Details
.fail_issue(name, code:, message:, fix:) ⇒ Object
76 77 78 79 80 81 82 83 84 |
# File 'lib/textus/doctor.rb', line 76 def fail_issue(name, code:, message:, fix:) { "code" => code, "level" => "error", "subject" => name.to_s, "message" => , "fix" => fix, } end |
.run(store, checks: nil) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/textus/doctor.rb', line 27 def run(store, checks: nil) selected_keys = checks ? Array(checks).map(&:to_s) : ALL_CHECKS unknown = selected_keys - ALL_CHECKS unless unknown.empty? raise UsageError.new( "unknown doctor check: #{unknown.first}. Valid checks: #{ALL_CHECKS.join(", ")}", ) end selected = CHECKS.select { |c| selected_keys.include?(c.name_key) } issues = selected.flat_map { |c| c.new(store).call } issues.concat(run_registered_checks(store)) summary = LEVELS.to_h { |l| [l, issues.count { |i| i["level"] == l }] } { "protocol" => Textus::PROTOCOL, "ok" => summary["error"].zero?, "issues" => issues, "summary" => summary, } end |
.run_registered_checks(store) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/textus/doctor.rb', line 49 def run_registered_checks(store) out = [] view = Store::View.new(store) store.registry.rpc_names(:check).each do |name| callable = store.registry.rpc_callable(:check, name) begin result = Timeout.timeout(DOCTOR_CHECK_TIMEOUT_SECONDS) { callable.call(store: view) } if result.is_a?(Array) out.concat(result.map { |h| h.transform_keys(&:to_s) }) else out << fail_issue(name, code: "doctor_check.bad_return", message: "doctor_check '#{name}' returned #{result.class} (expected Array)", fix: "return an array of issue hashes from the doctor_check block") end rescue Timeout::Error out << fail_issue(name, code: "doctor_check.timeout", message: "doctor_check '#{name}' exceeded #{DOCTOR_CHECK_TIMEOUT_SECONDS}s", fix: "shorten the check or split it into smaller checks") rescue StandardError => e out << fail_issue(name, code: "doctor_check.failed", message: "#{e.class}: #{e.}", fix: "fix the doctor_check block in .textus/extensions/") end end out end |