Class: BackupNexus::Backup

Inherits:
BaseRecord
  • Object
show all
Defined in:
app/models/backup_nexus/backup.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.cleanup!(retention_days: 30) ⇒ Object

Cleanup old backup records



81
82
83
# File 'app/models/backup_nexus/backup.rb', line 81

def self.cleanup!(retention_days: 30)
  where("started_at < ?", retention_days.days.ago).delete_all
end

.health_summary(alert_threshold_hours: 24) ⇒ Object

Get backup health summary



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'app/models/backup_nexus/backup.rb', line 57

def self.health_summary(alert_threshold_hours: 24)
  configs = BackupNexus::BackupConfig.pluck(:name)
  results = configs.map do |config_name|
    latest = by_config(config_name).successful.latest_first.first
    age_hours = latest ? ((Time.current - latest.started_at) / 3600).round(1) : nil

    {
      config_name: config_name,
      last_backup: latest&.started_at,
      age_hours: age_hours,
      status: age_hours.nil? ? "unknown" : (age_hours < alert_threshold_hours ? "healthy" : "stale"),
      success_rate: success_rate(config_name: config_name),
      last_file_size: latest&.file_size
    }
  end

  {
    healthy: results.all? { |r| r[:status] == "healthy" },
    models: results,
    alerts: results.select { |r| r[:status] == "stale" || r[:status] == "unknown" }
  }
end

.start!(config_name:, triggered_by: "system") ⇒ Object

Start tracking a backup run



19
20
21
22
23
24
25
26
# File 'app/models/backup_nexus/backup.rb', line 19

def self.start!(config_name:, triggered_by: "system")
  create!(
    config_name: config_name,
    status: "running",
    triggered_by: triggered_by,
    started_at: Time.current
  )
end

.success_rate(config_name:, days: 7) ⇒ Object

Get success rate for a model over the last N days



50
51
52
53
54
# File 'app/models/backup_nexus/backup.rb', line 50

def self.success_rate(config_name:, days: 7)
  records = by_config(config_name).where("started_at >= ?", days.days.ago).where.not(status: "running")
  return 0 if records.empty?
  (records.successful.count.to_f / records.count * 100).round(1)
end

Instance Method Details

#duration_humanObject

Duration formatted



98
99
100
101
102
103
104
105
# File 'app/models/backup_nexus/backup.rb', line 98

def duration_human
  return "" unless duration
  if duration < 60
    "#{duration.round(1)}s"
  else
    "#{(duration / 60).floor}m #{(duration % 60).round}s"
  end
end

#fail!(error_message:) ⇒ Object

Mark backup as failed



40
41
42
43
44
45
46
47
# File 'app/models/backup_nexus/backup.rb', line 40

def fail!(error_message:)
  update!(
    status: "failed",
    error_message: error_message,
    duration: (Time.current - started_at).round(2),
    completed_at: Time.current
  )
end

#file_size_humanObject

Format file size



86
87
88
89
90
91
92
93
94
95
# File 'app/models/backup_nexus/backup.rb', line 86

def file_size_human
  return "" unless file_size
  units = ["B", "KB", "MB", "GB"]
  size = file_size.to_f
  units.each do |unit|
    return "#{size.round(1)} #{unit}" if size < 1024
    size /= 1024
  end
  "#{size.round(1)} TB"
end

#succeed!(file_path: nil, file_size: nil) ⇒ Object

Mark backup as completed



29
30
31
32
33
34
35
36
37
# File 'app/models/backup_nexus/backup.rb', line 29

def succeed!(file_path: nil, file_size: nil)
  update!(
    status: "success",
    file_path: file_path,
    file_size: file_size,
    duration: (Time.current - started_at).round(2),
    completed_at: Time.current
  )
end