.NET Core GitLab CI部署IIS报错:文件被其他进程占用
解决GitLab CI部署.NET Core API到IIS时的文件占用问题
当停止IIS应用池后仍出现The process cannot access the file because it is being used by another process错误,通常是因为应用池对应的进程(如w3wp.exe或dotnet.exe)未完全退出,或是有其他进程占用了目标目录的文件。以下是针对性解决方案:
1. 停止应用池后强制终止关联进程
在停止应用池后,添加脚本杀死残留的w3wp和dotnet进程,确保文件完全释放:
修改deploy阶段的脚本如下:
# 停止目标应用池 if((Get-WebAppPoolState -Name $application_pool_name).Value -ne 'Stopped'){ Write-Output ('Stopping Application Pool: {0}' -f $application_pool_name) Stop-WebAppPool -Name $application_pool_name } # 等待进程开始退出,然后终止关联的w3wp进程 Start-Sleep -s 2 Get-WmiObject Win32_Process -Filter "Name='w3wp.exe'" | Where-Object { $_.GetOwner().User -eq "IIS APPPOOL\$application_pool_name" } | ForEach-Object { Write-Output ('Killing w3wp process with ID: {0}' -f $_.ProcessId) Stop-Process -Id $_.ProcessId -Force } # 检查并终止占用发布目录的dotnet进程 Get-Process dotnet -ErrorAction SilentlyContinue | Where-Object { $_.MainModule -and $_.MainModule.FileName.StartsWith($iis_application_path) } | ForEach-Object { Write-Output ('Killing dotnet process with ID: {0}' -f $_.ProcessId) Stop-Process -Id $_.ProcessId -Force } # 执行文件复制 Copy-Item ($publish_path + "*") -Destination $iis_application_path -Recurse -Force -PassThru # 重启应用池 if((Get-WebAppPoolState -Name $application_pool_name).Value -ne 'Started'){ Write-Output ('Starting Application Pool: {0}' -f $application_pool_name) Start-WebAppPool -Name $application_pool_name }
2. 采用备份替换的方式避免文件占用
如果进程终止仍无效,可以先将原部署目录重命名为备份,再复制新文件,彻底规避文件占用问题:
修改deploy阶段的复制步骤为:
# 停止应用池及清理进程(同方案1的停止/杀进程代码) ... # 备份原部署目录 $backup_path = "$iis_application_path`_backup_$(Get-Date -Format 'yyyyMMddHHmmss')" if(Test-Path $iis_application_path){ Rename-Item -Path $iis_application_path -NewName $backup_path -Force } # 复制新发布文件 Copy-Item ($publish_path + "*") -Destination $iis_application_path -Recurse -Force -PassThru # 可选:清理备份目录(建议先验证部署成功后再启用) # Remove-Item -Path $backup_path -Recurse -Force -ErrorAction SilentlyContinue # 重启应用池 ...
3. 确保应用池完全停止后再执行复制
替换固定等待时间为循环检查应用池状态,直到确认完全停止:
if((Get-WebAppPoolState -Name $application_pool_name).Value -ne 'Stopped'){ Write-Output ('Stopping Application Pool: {0}' -f $application_pool_name) Stop-WebAppPool -Name $application_pool_name # 循环检查应用池状态,最多等待30秒 $timeout = 30 $elapsed = 0 while((Get-WebAppPoolState -Name $application_pool_name).Value -ne 'Stopped' -and $elapsed -lt $timeout){ Start-Sleep -s 1 $elapsed++ } if($elapsed -ge $timeout){ Write-Warning "Application pool $application_pool_name did not stop within 30 seconds" } }
内容的提问来源于stack exchange,提问作者Askarc Ali
相关产品推荐
相关产品推荐

