From c9baae92053b36ef2df278ebc9ca16b680f46eb3 Mon Sep 17 00:00:00 2001 From: Elson Vinicius de Souza Lopes Date: Tue, 29 Sep 2026 09:24:53 -0300 Subject: [PATCH] fix(ci-dev): sobe o sidecar LayoutParserDecrypt como tarefa agendada e injeta LayoutParserDecrypt__BaseUrl Desde o #569 a API descriptografa via HTTP (LayoutParserDecrypt:BaseUrl). O deploy dev nao entregava a config (appsettings.json do destino e preservado) nem subia o sidecar, entao o decryptor ficava Degraded, o catalogo vazio e o smoke test /health/ready falhava (runs 36479461190 e 36494454696). - Env do servico da API: LayoutParserDecrypt__BaseUrl=http://localhost:5220/. - Novo step antes da copia: para a tarefa agendada e o processo do sidecar. - Novo step antes do smoke test: recria a tarefa LayoutParserDecrypt-Sidecar (ONSTART, SYSTEM, `LayoutParserDecrypt.exe 5220`, restart em falha), valida porta livre e aguarda GET /health 200 (~60s), com diagnostico (estado da tarefa, processo, fim do log) sem segredos. - Motivo da tarefa agendada: o Decrypt e exe de console (HttpListener, sem ServiceBase) e nao pode ser registrado com sc.exe (erro 1053). - Smoke test da API e workflows Linux inalterados. Pre-requisitos do host dev (NAO verificados pelo CI; confirmados verbalmente pelo dono): runner pode registrar tarefa agendada como SYSTEM e a porta 5220 esta livre. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/ci-dev.yml | 113 +++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/.github/workflows/ci-dev.yml b/.github/workflows/ci-dev.yml index 7b80e3f..4af274c 100644 --- a/.github/workflows/ci-dev.yml +++ b/.github/workflows/ci-dev.yml @@ -403,6 +403,35 @@ jobs: Write-Host "Servico NSSM removido - sera recriado como nativo." } + # -- Sidecar Decrypt: parar a tarefa agendada ANTES de copiar (fix pos-#569) --------- + # + # Desde o #569 a API descriptografa via HTTP (LayoutParserDecrypt:BaseUrl), nao mais por + # Process.Start. O LayoutParserDecrypt.exe e um exe de CONSOLE (HttpListener em + # http://localhost:/, sem ServiceBase) - nao pode ser registrado com `sc.exe create` + # (erro 1053). Por isso roda como TAREFA AGENDADA (ONSTART, conta SYSTEM), nome fixo abaixo. + # Aqui so paramos a tarefa e o processo para liberar o .exe antes da copia; o registro e o + # start ficam no step "Registrar e iniciar sidecar Decrypt", depois da copia. + # + # PRE-REQUISITOS DO HOST DEV (NAO verificados pelo CI; confirmados verbalmente pelo dono): + # - o runner pode registrar tarefa agendada como SYSTEM (runner com privilegio de admin); + # - a porta 5220 esta livre (ou escolha outra e alinhe LayoutParserDecrypt__BaseUrl). + - name: Parar sidecar Decrypt (tarefa agendada) + run: | + $taskName = "LayoutParserDecrypt-Sidecar" + $task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue + if ($task) { + Write-Host "Tarefa $taskName existente (estado: $($task.State)) - parando..." + Stop-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue + } else { + Write-Host "Tarefa $taskName ainda nao existe - sera criada adiante." + } + # Garante que nenhum LayoutParserDecrypt.exe siga segurando o arquivo (best-effort). + Get-Process -Name "LayoutParserDecrypt" -ErrorAction SilentlyContinue | ForEach-Object { + Write-Host "Encerrando processo LayoutParserDecrypt PID $($_.Id)..." + Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue + } + Start-Sleep -Seconds 2 + - name: Backup do appsettings e copia dos artefatos run: | $DEPLOY_PATH = $env:DEPLOY_PATH_RESOLVED @@ -702,6 +731,12 @@ jobs: # em LowCodeCandidatesBudget.cs. Nada a configurar aqui - o default de 90s ja e seguro. $envList += "LowCode__RunnerTimeoutSeconds=180" + # LayoutParserDecrypt__BaseUrl - desde o #569 a API descriptografa via HTTP no sidecar + # (step "Registrar e iniciar sidecar Decrypt"). O appsettings.json do destino e PRESERVADO, + # entao a chave do repo nao chega ao dev: sem esta env var, BaseUrl fica vazio, o decryptor + # fica Degraded e o catalogo sobe vazio. Porta 5220 = default do sidecar; manter coerente. + $envList += "LayoutParserDecrypt__BaseUrl=http://localhost:5220/" + # LowCode__RunnerPath - resolvido pelo step de publicacao acima (aponta para # \api\lowcode-runner\LayoutParserLowCodeRunner.exe, copia da pasta Functions/ do # repo). So e definido quando o runner foi realmente publicado; do contrario a chave nao @@ -737,6 +772,84 @@ jobs: Write-Host "Ambiente do servico configurado ($($envList.Count) variavel(is) definida(s))." Write-Host " Chaves: $(($envList | ForEach-Object { ($_ -split '=', 2)[0] }) -join ', ')" + # -- Sidecar Decrypt: registrar a tarefa agendada, iniciar e aguardar /health ------- + # Roda depois da copia dos artefatos e ANTES do smoke test da API: sem o sidecar de pe, + # o catalogo sobe vazio (decryptor Degraded) e o /health/ready da API nunca fica 200. + # Idempotente: recria a tarefa a cada deploy. Falha o step (com diagnostico, sem segredos - + # o sidecar nao recebe nenhum segredo) se a tarefa nao subir ou o /health nao responder 200. + # Pre-requisitos do host dev: ver comentario do step "Parar sidecar Decrypt". + - name: Registrar e iniciar sidecar Decrypt + run: | + $taskName = "LayoutParserDecrypt-Sidecar" + $porta = 5220 + $healthUrl = "http://localhost:$porta/health" + $API_DEST = Join-Path $env:DEPLOY_PATH_RESOLVED "api" + $exePath = Join-Path $API_DEST "LayoutParserDecrypt.exe" + + if (-not (Test-Path $exePath)) { + Write-Error "LayoutParserDecrypt.exe nao encontrado em $exePath - o sidecar nao tem o que executar." + exit 1 + } + + # Porta precisa estar livre (o step anterior ja parou nossa instancia). + $ocupada = Get-NetTCPConnection -LocalPort $porta -State Listen -ErrorAction SilentlyContinue + if ($ocupada) { + $donos = ($ocupada | ForEach-Object { + $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue + "PID $($_.OwningProcess) ($(if ($p) { $p.ProcessName } else { 'desconhecido' }))" + }) -join ', ' + Write-Error "Porta $porta ja esta em uso por: $donos. Libere a porta ou ajuste porta/LayoutParserDecrypt__BaseUrl." + exit 1 + } + + # Recria a tarefa (idempotente): ONSTART, SYSTEM, sem limite de tempo, restart em falha. + if (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue) { + Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction Stop + } + try { + $action = New-ScheduledTaskAction -Execute $exePath -Argument "$porta" -WorkingDirectory $API_DEST + $trigger = New-ScheduledTaskTrigger -AtStartup + $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest + $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) ` + -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) ` + -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -MultipleInstances IgnoreNew + Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger ` + -Principal $principal -Settings $settings ` + -Description "LayoutParserDecrypt sidecar HTTP (porta $porta) - deploy via CI dev" -ErrorAction Stop | Out-Null + Write-Host "Tarefa $taskName registrada (ONSTART, SYSTEM, $exePath $porta)." + Start-ScheduledTask -TaskName $taskName -ErrorAction Stop + } catch { + Write-Error "Falha ao registrar/iniciar a tarefa ${taskName}: $($_.Exception.Message). Verifique se o runner pode criar tarefa agendada como SYSTEM." + exit 1 + } + + # Aguarda /health responder 200 (ate ~60s). + $ok = $false + for ($i = 1; $i -le 30; $i++) { + try { + $resp = Invoke-WebRequest -Uri $healthUrl -UseBasicParsing -TimeoutSec 3 + if ([int]$resp.StatusCode -eq 200) { $ok = $true; break } + } catch { } + Start-Sleep -Seconds 2 + } + + if (-not $ok) { + Write-Host "--- Diagnostico do sidecar Decrypt ---" + $info = Get-ScheduledTaskInfo -TaskName $taskName -ErrorAction SilentlyContinue + if ($info) { Write-Host "Ultimo resultado da tarefa: $($info.LastTaskResult) (estado: $((Get-ScheduledTask -TaskName $taskName).State))" } + $proc = Get-Process -Name "LayoutParserDecrypt" -ErrorAction SilentlyContinue + Write-Host ("Processo LayoutParserDecrypt: " + $(if ($proc) { "rodando (PID $($proc.Id))" } else { "NAO esta rodando" })) + $logDir = Join-Path $API_DEST "logs" + $ultimo = Get-ChildItem -Path $logDir -Filter "*ecrypt*" -File -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if ($ultimo) { + Write-Host "--- Fim de $($ultimo.Name) ---" + Get-Content -Path $ultimo.FullName -Tail 20 -ErrorAction SilentlyContinue | ForEach-Object { Write-Host $_ } + } + Write-Error "Sidecar Decrypt nao respondeu HTTP 200 em $healthUrl em ~60s. Deploy de dev abortado antes do smoke test da API." + exit 1 + } + Write-Host "Sidecar Decrypt OK: HTTP 200 em $healthUrl." + - name: Iniciar servico e smoke test run: | $serviceName = "LayoutParserApi"