Module: Ibex::GenerationTransactionRecovery
- Included in:
- GenerationTransaction
- Defined in:
- lib/ibex/generation_transaction_recovery.rb,
sig/ibex/generation_transaction_recovery.rbs
Overview
Failure recovery and best-effort cleanup for GenerationTransaction.
Instance Method Summary collapse
- #cleanup_artifacts(preserve_backups:) ⇒ Array[String]
-
#failure_details(cause, rollback, cleanup, sync, recovery) ⇒ Array[String]
rubocop:disable Layout/LineLength.
- #handle_failure(cause) ⇒ bot
- #recovery_artifacts ⇒ Array[String]
- #remove_artifact(path, failures) ⇒ void
- #rollback ⇒ Array[String]
- #rollback_record(record) ⇒ void
- #source_change_clean?(cause, rollback, cleanup, sync) ⇒ Boolean
- #sync_directories_best_effort ⇒ Array[String]
Instance Method Details
#cleanup_artifacts(preserve_backups:) ⇒ Array[String]
79 80 81 82 83 84 85 86 87 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 79 def cleanup_artifacts(preserve_backups:) failures = [] #: Array[String] @records.each do |record| paths = [record[:stage]] paths << record[:backup] unless preserve_backups paths.compact.each { |path| remove_artifact(path, failures) } end failures end |
#failure_details(cause, rollback, cleanup, sync, recovery) ⇒ Array[String]
rubocop:disable Layout/LineLength
31 32 33 34 35 36 37 38 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 31 def failure_details(cause, rollback, cleanup, sync, recovery) details = [cause.] details << "rollback failed: #{rollback.join('; ')}" unless rollback.empty? details << "cleanup failed: #{cleanup.join('; ')}" unless cleanup.empty? details << "directory sync failed: #{sync.join('; ')}" unless sync.empty? details << "recovery artifacts: #{recovery.join(', ')}" unless recovery.empty? details end |
#handle_failure(cause) ⇒ bot
10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 10 def handle_failure(cause) rollback_failures = rollback cleanup_failures = cleanup_artifacts(preserve_backups: !rollback_failures.empty?) sync_failures = sync_directories_best_effort raise cause if source_change_clean?(cause, rollback_failures, cleanup_failures, sync_failures) recovery = recovery_artifacts details = failure_details(cause, rollback_failures, cleanup_failures, sync_failures, recovery) raise GenerationTransaction::Error.new( "(generation):1:1: #{details.join(' | ')}", rollback_failed: !rollback_failures.empty?, recovery_artifacts: recovery ), cause: cause end |
#recovery_artifacts ⇒ Array[String]
42 43 44 45 46 47 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 42 def recovery_artifacts @records.filter_map do |record| backup = record[:backup] backup if backup && File.exist?(backup) end end |
#remove_artifact(path, failures) ⇒ void
This method returns an undefined value.
90 91 92 93 94 95 96 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 90 def remove_artifact(path, failures) File.unlink(path) rescue Errno::ENOENT nil rescue StandardError => e failures << "#{path}: #{e.}" end |
#rollback ⇒ Array[String]
50 51 52 53 54 55 56 57 58 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 50 def rollback failures = [] #: Array[String] @records.reverse_each do |record| rollback_record(record) rescue StandardError => e failures << "#{record.fetch(:target)}: #{e.}" end failures end |
#rollback_record(record) ⇒ void
This method returns an undefined value.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 61 def rollback_record(record) target = record.fetch(:target) if record.fetch(:backed_up) if record.fetch(:installed) File.rename(record.fetch(:backup), target) else File.unlink(record.fetch(:backup)) end record[:backup] = nil record[:backed_up] = false record[:installed] = false elsif record.fetch(:installed) File.unlink(target) record[:installed] = false end end |
#source_change_clean?(cause, rollback, cleanup, sync) ⇒ Boolean
25 26 27 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 25 def source_change_clean?(cause, rollback, cleanup, sync) cause.is_a?(GenerationTransaction::SourceChanged) && rollback.empty? && cleanup.empty? && sync.empty? end |
#sync_directories_best_effort ⇒ Array[String]
99 100 101 102 103 104 105 106 107 |
# File 'lib/ibex/generation_transaction_recovery.rb', line 99 def sync_directories_best_effort failures = [] #: Array[String] @records.map { |record| record.fetch(:directory) }.uniq.sort.each do |directory| File.open(directory, File::RDONLY, &:fsync) rescue StandardError => e failures << "#{directory}: #{e.}" end failures end |