🐝 F2.T2: Condicionales --on-error abort|continue|retry

- abort: detiene al primer fallo (default)
- continue: salta el fallo y sigue con el siguiente
- retry: reintenta N veces antes de abortar (--retries N)
- Resumen final con conteo de éxitos/fallos/saltados
This commit is contained in:
Ricardo Monla
2026-04-09 12:25:45 -03:00
parent b7c2e316c0
commit a0440b89d9
+50 -8
View File
@@ -767,11 +767,13 @@ module ADN
# ─── Orquestador: 1 dron por archivo ──────────────────────────
def cmd_orquestar(args)
options = {}
options = { on_error: 'abort', retries: 2 }
OptionParser.new do |opts|
opts.banner = "Uso: ./adn/tools/run bkps orquestar <T1|ID> [opciones]"
opts.on("--timeout N", Integer, "Timeout por dron en segundos (default: 7200)") { |t| options[:timeout] = t }
opts.on("--dry-run", "Solo listar archivos sin lanzar drones") { options[:dry_run] = true }
opts.on("--on-error MODE", %w[abort continue retry], "Qué hacer si un dron falla (abort|continue|retry, default: abort)") { |m| options[:on_error] = m }
opts.on("--retries N", Integer, "Número de reintentos si --on-error retry (default: 2)") { |n| options[:retries] = n }
end.parse!(args)
ref = args.shift
@@ -813,6 +815,7 @@ module ADN
puts " Total archivos: #{archivos.length}"
puts " Pendientes: #{pendientes.length}"
puts " Ya procesados: #{archivos.length - pendientes.length}"
puts " On-error: #{options[:on_error]}#{options[:on_error] == 'retry' ? " (max #{options[:retries]})" : ''}"
puts ""
if pendientes.empty?
@@ -823,36 +826,75 @@ module ADN
adn_run = File.join(ADN::PROJECT_ROOT, 'adn', 'tools', 'run')
timeout = options[:timeout] || 7200
# Tracking de resultados
resultados = []
abortado = false
pendientes.each_with_index do |arch, i|
tamaño_gb = (arch[:tamaño].to_f / 1024**3).round(1)
puts " #{Color::BOLD}[#{i+1}/#{pendientes.length}]#{Color::RESET} #{arch[:vm]}#{arch[:archivo]} (#{tamaño_gb}GB)"
if options[:dry_run]
puts " #{Color::YELLOW}[DRY-RUN] Lanzaría dron para: #{arch[:archivo]}#{Color::RESET}"
resultados << { vm: arch[:vm], estado: :skipped }
next
end
# Lanzar dron atómico para este archivo
# Lanzar dron atómico con reintentos
nota = "Comprimir #{arch[:vm]} (#{tamaño_gb}GB)"
cmd_dron = "#{adn_run} dron lanzar" \
" --nota \"#{nota}\"" \
" --timeout #{timeout}" \
" -- #{adn_run} bkps run #{ref} --batch --archivo #{Shellwords.escape(arch[:archivo])}"
puts " 🛸 Lanzando dron..."
resultado = system(cmd_dron)
max_intentos = options[:on_error] == 'retry' ? options[:retries] + 1 : 1
exito = false
if resultado
max_intentos.times do |intento|
etiqueta = max_intentos > 1 ? " (intento #{intento + 1}/#{max_intentos})" : ""
puts " 🛸 Lanzando dron#{etiqueta}..."
exito = system(cmd_dron)
break if exito
if intento < max_intentos - 1
puts " #{Color::YELLOW}⟳ Reintentando...#{Color::RESET}"
end
end
if exito
puts " #{Color::GREEN}✔ Dron completado#{Color::RESET}"
resultados << { vm: arch[:vm], estado: :ok }
else
puts " #{Color::RED}✖ Dron falló — deteniendo orquestación#{Color::RESET}"
break
resultados << { vm: arch[:vm], estado: :failed }
case options[:on_error]
when 'abort'
puts " #{Color::RED}✖ Dron falló — deteniendo orquestación#{Color::RESET}"
abortado = true
break
when 'continue'
puts " #{Color::YELLOW}⚠ Dron falló — continuando con el siguiente#{Color::RESET}"
when 'retry'
puts " #{Color::RED}✖ Dron falló después de #{max_intentos} intentos — deteniendo#{Color::RESET}"
abortado = true
break
end
end
puts ""
end
puts "#{Color::BOLD}🐝 Orquestación finalizada.#{Color::RESET}"
# Resumen final
ok = resultados.count { |r| r[:estado] == :ok }
failed = resultados.count { |r| r[:estado] == :failed }
puts "\n#{Color::BOLD}🐝 Resumen de Orquestación#{Color::RESET}"
puts "" * 40
puts " ✅ Exitosos: #{ok}"
puts " ❌ Fallidos: #{failed}" if failed > 0
puts " ⏭️ Saltados: #{pendientes.length - ok - failed}" if abortado
puts "#{Color::BOLD}🐝 Orquestación #{abortado ? 'abortada' : 'finalizada'}.#{Color::RESET}"
exit 1 if failed > 0
end
def ejecutar_comando(comando, options = {})