# Exact Apache instance graceful reload; no termination, service registration or QA control. # Apache 2.4.54 uses ap_restart for graceful Windows restarts. # https://github.com/apache/httpd/blob/2.4.54/server/mpm/winnt/mpm_winnt.c#L144-L242 param([switch]$Apply) $ErrorActionPreference='Stop' $taskRoot='C:\laragon\www\portal-investidor' $taskPrivate=Join-Path $taskRoot 'storage\app\private\investmoz-v2\portal-audit' $revision='41caea0f900fe0705e84e065a65f9534ff3a585ee34098f860666f522875a3a5' $apacheRoot='C:\laragon\bin\apache\httpd-2.4.54-win64-VS16' $exe=Join-Path $apacheRoot 'bin\httpd.exe' $configuration=Join-Path $apacheRoot 'conf\httpd.conf' $vhost='C:\laragon\etc\apache2\sites-enabled\portal-investidor.test.conf' $parent=Get-CimInstance Win32_Process -Filter 'ProcessId=6108' if(-not $parent -or $parent.ExecutablePath -ne $exe -or $parent.CreationDate.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss') -ne '2026-10-11T10:33:16' -or $parent.CommandLine -notlike '*-f C:/laragon/bin/apache/httpd-2.4.54-win64-VS16/conf/httpd.conf*'){throw 'Exact authorized portal Apache instance differs; no signal sent'} if(([IO.File]::ReadAllText((Join-Path $apacheRoot 'logs\httpd.pid'))).Trim() -ne '6108'){throw 'Apache PID file differs'} if((Get-FileHash -LiteralPath $vhost -Algorithm SHA256).Hash.ToLowerInvariant() -ne 'a62c5d000e4313b21c89423303dd277ee7ce98eedd0de94f9d32b4246297f9ec'){throw 'Staged authorized vhost differs'} $stage=Get-Content -LiteralPath (Join-Path $taskPrivate 'workflow-activation-stage.json') -Raw -Encoding UTF8|ConvertFrom-Json if($stage.revision -ne $revision -or $stage.authenticated_schema_installed -or $stage.bootstrap_executed){throw 'Unexpected activation stage'} $before=@(Get-CimInstance Win32_Process -Filter 'Name="httpd.exe"'|Where-Object {$_.ParentProcessId -eq 6108}|Select-Object -ExpandProperty ProcessId) if($before.Count -ne 1 -or $before[0] -ne 10812){throw 'Exact original child differs; inspect before any signal'} $phpDirectory='C:\laragon\bin\php\php-8.5.11-Win32-vs17-x64' $env:PATH=$phpDirectory+';'+$env:PATH $syntaxProcess=Start-Process -FilePath $exe -ArgumentList @('-d',$apacheRoot,'-f',$configuration,'-t') -WindowStyle Hidden -Wait -PassThru -RedirectStandardOutput (Join-Path $taskPrivate 'workflow-activation-apache-reload-syntax.stdout.log') -RedirectStandardError (Join-Path $taskPrivate 'workflow-activation-apache-reload-syntax.stderr.log') if($syntaxProcess.ExitCode -ne 0){throw 'Apache syntax invalid; no signal sent'} $event=[Threading.EventWaitHandle]::OpenExisting('ap6108_restart',[Security.AccessControl.EventWaitHandleRights]::Modify) $receipt=@{at=[DateTime]::UtcNow.ToString('o');revision=$revision;parent_pid=6108;previous_child=10812;mechanism='Apache own graceful Windows restart event';normal_Laragon_control_did_not_reload_manual_instance=$true;scope='portal Apache only; QA Apache, PostgreSQL, schema, data and keys untouched';signal_sent=$false;syntax_passed=$true;new_child_pid=$null} try{ if($Apply){ if(-not $event.Set()){throw 'Apache restart event not accepted'} $receipt.signal_sent=$true $deadline=[DateTime]::UtcNow.AddSeconds(55) do{ Start-Sleep -Milliseconds 500 $children=@(Get-CimInstance Win32_Process -Filter 'Name="httpd.exe"'|Where-Object {$_.ParentProcessId -eq 6108 -and $_.ExecutablePath -eq $exe -and $_.ProcessId -ne 10812}) if($children.Count -eq 1 -and -not (Get-Process -Id 10812 -ErrorAction SilentlyContinue)){break} }while([DateTime]::UtcNow -lt $deadline) if($children.Count -ne 1 -or (Get-Process -Id 10812 -ErrorAction SilentlyContinue)){throw 'Graceful restart not observed within bounded window; do not terminate processes'} $receipt.new_child_pid=$children[0].ProcessId $receipt.result='graceful_reload_observed_pending_web_verification' }else{$receipt.result='exact_instance_and_own_restart_event_verified_no_signal'} }finally{ $event.Dispose() [IO.File]::WriteAllText((Join-Path $taskPrivate $(if($Apply){'workflow-activation-apache-reload.json'}else{'workflow-activation-apache-reload-preparation.json'})),($receipt|ConvertTo-Json -Depth 5),[Text.UTF8Encoding]::new($false)) } $receipt|ConvertTo-Json -Depth 5