Windows环境下GitHub Actions多步骤后台进程存活问题求助
问题
在GitHub Actions任务中,尝试在一个步骤启动本地服务器,后续步骤连接该服务器。此流程在Linux上可正常运行,但在Windows环境中,所有后台进程会在进入下一步前被终止,导致名为“Connect to server again (Windows)”的步骤执行失败。原工作流配置如下:
name: Test on: push: branches: - '*' workflow_dispatch: jobs: micro-server: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest] steps: - name: Create index.html run: echo "<h1>Hello world!</h1>" > index.html - name: Install dotnet-serve run: dotnet tool install --global dotnet-serve - name: Start server and connect to server (Windows) if: ${{ matrix.os == 'windows-latest' }} run: | $env:RUNNER_TRACKING_ID="" $web = Start-Job { dotnet serve --port 5100 } -WorkingDirectory $pwd $timeout = 30 $startTime = Get-Date do { $elapsedTime = (Get-Date) - $startTime if ($elapsedTime.TotalSeconds -ge $timeout) { Write-Host "Timeout reached. Server not available after $($elapsedTime.TotalSeconds) seconds." exit 1 } try { $response = Invoke-WebRequest -Uri "http://localhost:5100" -UseBasicParsing -Method Head -TimeoutSec 2 $serverAvailable = $response.StatusCode -eq 200 } catch { $serverAvailable = $false } if (-not $serverAvailable) { Write-Host "Waiting for server to become available... Elapsed time: $($elapsedTime.ToString('hh\:mm\:ss'))" Start-Sleep -Seconds 1 # Wait for 1 second before checking again } } while (-not $serverAvailable) $totalWaitTime = (Get-Date) - $startTime Write-Host "Server is now available after $($totalWaitTime.ToString('hh\:mm\:ss'))." Get-Process | Where-Object { $_.Modules.FileName -like "*dotnet*" } - name: List dotnet processes (Windows) if: ${{ matrix.os == 'windows-latest' }} run: | Get-Process | Where-Object { $_.Modules.FileName -like "*dotnet*" } - name: Connect to server again (Windows) if: ${{ matrix.os == 'windows-latest' }} run: | Invoke-WebRequest -Uri "http://localhost:5100" -UseBasicParsing -Method Head -TimeoutSec 2 - name: Start server and connect to server (Linux) if: ${{ matrix.os != 'windows-latest' }} run: | dotnet serve --port 5100 & sleep 5 curl http://localhost:5100 - name: Connect to server again (Linux) if: ${{ matrix.os != 'windows-latest' }} run: | curl http://localhost:5100
解决方案
方法1:用Start-Process启动独立进程
Windows上Start-Job创建的后台进程会随当前PowerShell会话结束而终止,改用Start-Process并配置参数让进程脱离当前会话,同时清除RUNNER_TRACKING_ID环境变量避免GitHub Actions自动清理进程:
修改Windows启动服务器的步骤:
- name: Start server and connect to server (Windows) if: ${{ matrix.os == 'windows-latest' }} run: | $env:RUNNER_TRACKING_ID="" # 启动dotnet-serve,使其脱离当前会话 $process = Start-Process dotnet -ArgumentList "serve --port 5100" -WorkingDirectory $pwd -NoNewWindow -PassThru $timeout = 30 $startTime = Get-Date do { $elapsedTime = (Get-Date) - $startTime if ($elapsedTime.TotalSeconds -ge $timeout) { Write-Host "Timeout reached. Server not available after $($elapsedTime.TotalSeconds) seconds." exit 1 } try { $response = Invoke-WebRequest -Uri "http://localhost:5100" -UseBasicParsing -Method Head -TimeoutSec 2 $serverAvailable = $response.StatusCode -eq 200 } catch { $serverAvailable = $false } if (-not $serverAvailable) { Write-Host "Waiting for server to become available... Elapsed time: $($elapsedTime.ToString('hh\:mm\:ss'))" Start-Sleep -Seconds 1 } } while (-not $serverAvailable) $totalWaitTime = (Get-Date) - $startTime Write-Host "Server is now available after $($totalWaitTime.ToString('hh\:mm\:ss'))."
方法2:将服务器注册为临时Windows服务
使用nssm(轻量服务管理工具)把dotnet-serve注册为Windows服务,服务进程不会随步骤会话终止而关闭:
- 安装nssm:
- name: Install nssm (Windows) if: ${{ matrix.os == 'windows-latest' }} run: | Invoke-WebRequest -Uri "https://nssm.cc/release/nssm-2.24.zip" -OutFile "nssm.zip" Expand-Archive -Path "nssm.zip" -DestinationPath "nssm" $nssmPath = Join-Path (Get-ChildItem -Path "nssm" -Directory | Select-Object -First 1).FullName "win64\nssm.exe" Copy-Item $nssmPath -Destination "C:\Windows\System32\nssm.exe"
- 注册并启动服务:
- name: Start dotnet-serve as service (Windows) if: ${{ matrix.os == 'windows-latest' }} run: | $dotnetPath = (Get-Command dotnet).Source nssm install DotnetServe $dotnetPath nssm set DotnetServe AppParameters "serve --port 5100 --working-dir $pwd" nssm start DotnetServe # 等待服务启动完成 $timeout = 30 $startTime = Get-Date do { $elapsedTime = (Get-Date) - $startTime if ($elapsedTime.TotalSeconds -ge $timeout) { Write-Host "Timeout waiting for service to start." exit 1 } try { $response = Invoke-WebRequest -Uri "http://localhost:5100" -UseBasicParsing -Method Head -TimeoutSec 2 if ($response.StatusCode -eq 200) { break } } catch { Start-Sleep -Seconds 1 } } while ($true)
- 测试完成后清理服务:
- name: Cleanup dotnet-serve service (Windows) if: ${{ matrix.os == 'windows-latest' }} run: | nssm stop DotnetServe nssm remove DotnetServe confirm
方法3:合并所有操作到单个步骤(快速替代)
如果不需要拆分多个步骤,可将服务器启动、所有连接检查合并到同一个步骤,避免会话终止导致进程被清理:
- name: Start server and run all checks (Windows) if: ${{ matrix.os == 'windows-latest' }} run: | $env:RUNNER_TRACKING_ID="" $web = Start-Job { dotnet serve --port 5100 } -WorkingDirectory $pwd # 等待服务器启动 $timeout = 30 $startTime = Get-Date do { $elapsedTime = (Get-Date) - $startTime if ($elapsedTime.TotalSeconds -ge $timeout) { Write-Host "Timeout reached." exit 1 } try { $response = Invoke-WebRequest -Uri "http://localhost:5100" -UseBasicParsing -Method Head -TimeoutSec 2 if ($response.StatusCode -eq 200) { break } } catch { Start-Sleep -Seconds 1 } } while ($true) # 执行第一次连接检查 Invoke-WebRequest -Uri "http://localhost:5100" -UseBasicParsing -Method Head -TimeoutSec 2 # 执行第二次连接检查(模拟原后续步骤) Invoke-WebRequest -Uri "http://localhost:5100" -UseBasicParsing -Method Head -TimeoutSec 2
内容的提问来源于stack exchange,提问作者PEK
相关产品推荐
相关产品推荐

