fix(windows): normalize packaging step scheduling priority
This commit is contained in:
1 parent
9c622fad96
commit
b6e387e5b3
8 files changed
+131
-2
No files matched your search
@@ -579,6 +579,9 @@ jobs:
|
||||
- name: Verify windowless Windows runner launcher
|
||||
shell: pwsh
|
||||
run: ./apps/desktop/tests/windows-runner-launcher.ps1
|
||||
- name: Verify packaging process priority inheritance
|
||||
shell: pwsh
|
||||
run: ./apps/desktop/tests/windows-packaging-priority.ps1
|
||||
- name: Run Windows observational gates on built artifacts
|
||||
id: observational
|
||||
continue-on-error: true
|
||||
|
||||
@@ -118,6 +118,7 @@ jobs:
|
||||
const branch=cp.execFileSync('git',['rev-parse','--abbrev-ref','HEAD'],{encoding:'utf8'}).trim();
|
||||
if(branch==='HEAD' || branch!==ref || ref.startsWith('refs/')) throw Error('Select a branch in this repository, not a SHA or PR ref');
|
||||
}
|
||||
if(!fs.existsSync('apps/desktop/scripts/windows-packaging-priority.ps1')) throw Error('Source lacks Windows packaging priority support; select a newer release');
|
||||
if(!fs.readFileSync('apps/desktop/scripts/desktop-ci-version.mjs','utf8').includes('PACKAGE_VERSION_MODE')) throw Error('Source lacks Desktop channel/version CI support; select a newer release');"
|
||||
- uses: pnpm/[email protected]
|
||||
with:
|
||||
@@ -154,6 +155,7 @@ jobs:
|
||||
- name: Install locked dependencies
|
||||
working-directory: ${{ steps.build_workspace.outputs.directory }}
|
||||
run: |
|
||||
& ./apps/desktop/scripts/windows-packaging-priority.ps1
|
||||
node -e "const os=require('node:os'); console.log(JSON.stringify({node:process.version,availableParallelism:os.availableParallelism(),logicalCpus:os.cpus().length,totalMemoryBytes:os.totalmem(),freeMemoryBytes:os.freemem()}))"
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
pnpm store path
|
||||
@@ -181,6 +183,7 @@ jobs:
|
||||
PACKAGE_VERSION: ${{ steps.settings.outputs.version }}
|
||||
PACKAGE_BUILD_TEMP: ${{ steps.build_workspace.outputs.temporaryDirectory }}
|
||||
run: |
|
||||
& ./apps/desktop/scripts/windows-packaging-priority.ps1
|
||||
if ($env:PACKAGE_BUILD_TEMP) {
|
||||
$env:TEMP = $env:PACKAGE_BUILD_TEMP
|
||||
$env:TMP = $env:PACKAGE_BUILD_TEMP
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
en: 5b4f0f80a117f202
|
||||
zh: ff05be196c181087
|
||||
/desktop-packaging/windows-actions-packaging:
|
||||
en: 330c905d2b610fc7
|
||||
zh: 1985b588241c4f95
|
||||
en: e628d75c47317979
|
||||
zh: 17055233501f4df6
|
||||
/desktop-packaging/macos-self-hosted-packaging:
|
||||
en: a3af9523fdc60036
|
||||
zh: 5e18d4740e9b7f57
|
||||
|
||||
@@ -117,6 +117,8 @@ For path-sensitive Windows build measurements, `build_root` optionally selects a
|
||||
|
||||
For cache measurements, `cache_namespace` selects a retained subdirectory for both dependency stores and upstream downloads; leave it empty for normal shared caches. Use a new name for a cold sample and repeat that name for warm samples. Names contain 1–64 lowercase letters, digits or hyphens, start with a letter or digit, and cannot be Windows device names. This does not reset the separate signature cache or OS file cache; report those states and Job start-to-completion time alongside phase timings and artifact size. Before dependency installation, the workflow records the Node version, available CPU parallelism, logical CPU count, and total/free memory.
|
||||
|
||||
The dependency-install and packaging steps normalize their own shell to normal CPU, I/O and memory priority before launching children, and record all three values before and after adjustment. Failure to establish these values stops the step. This does not modify the runner task, account, startup triggers or other processes.
|
||||
|
||||
<a id="macos-actions"></a>
|
||||
|
||||
## macOS self-hosted packaging
|
||||
|
||||
@@ -117,6 +117,8 @@ runner 的受监督启动和恢复见 [Windows runner 机器准备](../windows-s
|
||||
|
||||
测量缓存时,`cache_namespace` 为两个依赖 store 和上游下载选择保留的子目录;留空使用正常共享缓存。新名称用于冷缓存采样,再次使用同名用于热缓存采样。名称由 1–64 个小写字母、数字或连字符组成,以字母或数字开头,且不能为 Windows 设备名。这不会重置独立的签名缓存或操作系统文件缓存;应将其状态、Job 开始至完成的总耗时与阶段耗时和产物体积一并报告。workflow 在依赖安装前记录 Node 版本、可用 CPU 并行数、逻辑 CPU 数及总内存和空闲内存。
|
||||
|
||||
依赖安装和打包步骤在启动子进程前,将自身 shell 的 CPU、I/O 和内存优先级调整为普通值,并记录调整前后的三项值;无法确认调整成功时停止该步骤。这不会修改 runner 任务、账户、启动触发器或其他进程。
|
||||
|
||||
<a id="macos-actions"></a>
|
||||
|
||||
## macOS 自托管打包
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# Normalize only this workflow shell and the children it subsequently launches.
|
||||
[CmdletBinding()]
|
||||
param([switch]$InspectOnly)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if (-not $IsWindows) { throw 'Packaging process priority requires Windows.' }
|
||||
|
||||
if (-not ('DshPackagingPriority' -as [type])) {
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public static class DshPackagingPriority {
|
||||
[DllImport("kernel32.dll")] static extern IntPtr GetCurrentProcess();
|
||||
[DllImport("ntdll.dll")] static extern int NtSetInformationProcess(IntPtr process, int kind, ref int value, int size);
|
||||
[DllImport("ntdll.dll")] static extern int NtQueryInformationProcess(IntPtr process, int kind, out int value, int size, out int length);
|
||||
public static int Read(int kind) {
|
||||
int value, length;
|
||||
int status = NtQueryInformationProcess(GetCurrentProcess(), kind, out value, 4, out length);
|
||||
if (status != 0 || length != 4) throw new InvalidOperationException("Cannot read packaging priority: " + status);
|
||||
return value;
|
||||
}
|
||||
public static void Set(int kind, int value) {
|
||||
int status = NtSetInformationProcess(GetCurrentProcess(), kind, ref value, 4);
|
||||
if (status != 0) throw new InvalidOperationException("Cannot set packaging priority: " + status);
|
||||
}
|
||||
}
|
||||
'@
|
||||
}
|
||||
|
||||
$process = [Diagnostics.Process]::GetCurrentProcess()
|
||||
try {
|
||||
$before = [ordered]@{
|
||||
cpu = $process.PriorityClass.ToString()
|
||||
io = [DshPackagingPriority]::Read(33)
|
||||
memory = [DshPackagingPriority]::Read(39)
|
||||
}
|
||||
if (-not $InspectOnly) {
|
||||
$process.PriorityClass = [Diagnostics.ProcessPriorityClass]::Normal
|
||||
# PROCESSINFOCLASS: ProcessIoPriority (33), ProcessPagePriority (39).
|
||||
[DshPackagingPriority]::Set(33, 2)
|
||||
[DshPackagingPriority]::Set(39, 5)
|
||||
}
|
||||
$process.Refresh()
|
||||
$after = [ordered]@{
|
||||
cpu = $process.PriorityClass.ToString()
|
||||
io = [DshPackagingPriority]::Read(33)
|
||||
memory = [DshPackagingPriority]::Read(39)
|
||||
}
|
||||
[ordered]@{ event = 'packaging-process-priority'; before = $before; after = $after } | ConvertTo-Json -Compress
|
||||
if (-not $InspectOnly -and ($after.cpu -ne 'Normal' -or $after.io -ne 2 -or $after.memory -ne 5)) {
|
||||
throw 'Packaging process did not reach normal CPU, I/O and memory priority.'
|
||||
}
|
||||
} finally {
|
||||
$process.Dispose()
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# Exercise priority inheritance in disposable children without changing the test host or runner.
|
||||
[CmdletBinding()]
|
||||
param([switch]$Child)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if (-not $IsWindows) { throw 'Requires PowerShell 7 on Windows.' }
|
||||
$helper = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../scripts/windows-packaging-priority.ps1'))
|
||||
if ($Child) {
|
||||
$null = & $helper -InspectOnly
|
||||
$self = [Diagnostics.Process]::GetCurrentProcess()
|
||||
try {
|
||||
$self.PriorityClass = [Diagnostics.ProcessPriorityClass]::BelowNormal
|
||||
[DshPackagingPriority]::Set(33, 1)
|
||||
[DshPackagingPriority]::Set(39, 2)
|
||||
$report = (& $helper | ConvertFrom-Json)
|
||||
if ($report.before.cpu -ne 'BelowNormal' -or $report.before.io -ne 1 -or $report.before.memory -ne 2) {
|
||||
throw 'Fixture did not establish background priority.'
|
||||
}
|
||||
if ($report.after.cpu -ne 'Normal' -or $report.after.io -ne 2 -or $report.after.memory -ne 5) {
|
||||
throw 'Packaging shell retained background priority.'
|
||||
}
|
||||
$inherited = (& (Join-Path $PSHOME 'pwsh.exe') -NoProfile -File $helper -InspectOnly | ConvertFrom-Json)
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Priority inspection child failed.' }
|
||||
if ($inherited.before.cpu -ne 'Normal' -or $inherited.before.io -ne 2 -or $inherited.before.memory -ne 5) {
|
||||
throw 'Packaging child did not inherit normal priority.'
|
||||
}
|
||||
} finally {
|
||||
$self.Dispose()
|
||||
}
|
||||
exit 0
|
||||
}
|
||||
$process = [Diagnostics.Process]::new()
|
||||
$process.StartInfo.FileName = Join-Path $PSHOME 'pwsh.exe'
|
||||
$process.StartInfo.UseShellExecute = $false
|
||||
$process.StartInfo.CreateNoWindow = $true
|
||||
$process.StartInfo.RedirectStandardError = $true
|
||||
foreach ($argument in @('-NoProfile', '-File', $PSCommandPath, '-Child')) {
|
||||
$process.StartInfo.ArgumentList.Add($argument)
|
||||
}
|
||||
$started = $false
|
||||
try {
|
||||
$started = $process.Start()
|
||||
if (-not $started) { throw 'Could not start priority test.' }
|
||||
$errorOutput = $process.StandardError.ReadToEndAsync()
|
||||
if (-not $process.WaitForExit(30000)) { throw 'Priority test exceeded 30 seconds.' }
|
||||
if (-not $errorOutput.Wait(5000)) { throw 'Priority test error stream did not close.' }
|
||||
if ($process.ExitCode -ne 0) { throw "Priority test failed: $($process.ExitCode): $($errorOutput.Result)" }
|
||||
} finally {
|
||||
if ($started -and -not $process.HasExited) {
|
||||
$process.Kill($true)
|
||||
$process.WaitForExit()
|
||||
}
|
||||
$process.Dispose()
|
||||
}
|
||||
Write-Output 'Packaging priority normalization and child inheritance passed.'
|
||||
@@ -162,6 +162,16 @@ it('routes all packaging consumers to the selected workspace and removes it only
|
||||
}
|
||||
})
|
||||
|
||||
it('normalizes priority in the dependency and packaging shells before launching their children', () => {
|
||||
const command = '& ./apps/desktop/scripts/windows-packaging-priority.ps1'
|
||||
expect(job.steps.find(entry => entry.name === 'Validate selected source and adapter support')!.run)
|
||||
.toContain("fs.existsSync('apps/desktop/scripts/windows-packaging-priority.ps1')")
|
||||
for (const name of ['Install locked dependencies', 'Build installer and verify packaged runtime']) {
|
||||
const step = job.steps.find(entry => entry.name === name)!
|
||||
expect(step.run!.trimStart().startsWith(command + '\n')).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('scopes the optional temporary directory to installer building without changing Actions or later steps', () => {
|
||||
const build = job.steps.find(step => step.name === 'Build installer and verify packaged runtime')!
|
||||
expect(build.env?.PACKAGE_BUILD_TEMP).toBe('${{ steps.build_workspace.outputs.temporaryDirectory }}')
|
||||
|
||||
Reference in new issue
Block a user