From 84eccfe8cb82ad024fbab878b8c11df418d4ff96 Mon Sep 17 00:00:00 2001 From: kdletters Date: Tue, 19 May 2026 18:49:20 +0800 Subject: [PATCH] fix(jenkins): run server provision downloads on windows --- .hermes/shared-memory/decision-log.md | 3 ++- .hermes/shared-memory/pitfalls.md | 8 ++++++++ ...€å‘è¿ç»´ã€‘本地开å‘验è¯ä¸Žç”Ÿäº§è¿ç»´-2026-05-15.md | 2 +- .../Jenkinsfile.production-server-provision | 18 +++++++++++++++--- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index 9896b079..02a76a14 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -91,8 +91,9 @@ - èƒŒæ™¯ï¼šå½“å‰ `development` provision 目标实际就是 Linux agent `genarrative-build-01`ï¼Œä¹‹å‰æŠŠ `Prepare Provision Tools` 放在 `linux && genarrative-build` 会让目标机自己连 GitHub å’Œ `install.spacetimedb.com`,è¿èƒŒâ€œWindows 本机先下载å†ä¼ åˆ°ç›®æ ‡æœºâ€çš„è¿ç»´è¦æ±‚。 - 决策:`Genarrative-Server-Provision` æ‹†æˆ Windows 下载阶段和 Linux 目标机安装阶段。Windows 节点的 `Download Provision Tool Archives` åªä¸‹è½½ SpacetimeDB 官方安装脚本ã€Linux update installer å’Œ `otelcol-contrib_0.151.0_linux_amd64.tar.gz`,通过 `stash/unstash` 传到目标 Linux 节点;目标机执行 `scripts/prepare-server-provision-tools.sh` 时设置 `PROVISION_REQUIRE_LOCAL_DOWNLOADS=true`ï¼Œåªæ¶ˆè´¹å·²ä¸‹è½½ä»¶ç”Ÿæˆ `provision-tools/`,缺包直接失败,ä¸å›žé€€å¤–网下载。 +- 追加决策:Server-Provision çš„ Windows helper ä¸å†å¯¹ Jenkins `writeFile` 刚写出的 `.ps1` åšåŽŸåœ° UTF-8 BOM é‡å†™ï¼Œè€Œæ˜¯ç”±æ˜¾å¼ `powershell.exe` 按 UTF-8 读入脚本文本,并用 `ScriptBlock::Create(...)` 在内存中执行;这样既ä¿ç•™ä¸­æ–‡è„šæœ¬å†…å®¹ï¼Œåˆé¿å…åŒä¸€ä¸ª workspace 脚本被立å³é‡å†™æ—¶è§¦å‘ `æ‹’ç»è®¿é—®`。 - å½±å“范围:`jenkins/Jenkinsfile.production-server-provision`ã€`scripts/prepare-server-provision-tools.sh`ã€`scripts/jenkins-server-provision.sh`ã€ç”Ÿäº§è¿ç»´æ–‡æ¡£ã€‚ -- éªŒè¯æ–¹å¼ï¼šJenkins 日志应先出现 Windows 节点的 `[prepare-provision-downloads]` 下载日志,å†åœ¨ `genarrative-build-01` 上出现“使用已下载的 ...â€æ—¥å¿—;目标机ä¸åº”出现直接访问 `install.spacetimedb.com` 或 OpenTelemetry GitHub release 下载地å€çš„回退日志。 +- éªŒè¯æ–¹å¼ï¼šJenkins 日志应先出现 Windows 节点的 `[jenkins-powershell] workspace:`ã€`[jenkins-powershell] loaded bytes:` å’Œ `[prepare-provision-downloads]` 下载日志,å†åœ¨ `genarrative-build-01` 上出现“使用已下载的 ...â€æ—¥å¿—;目标机ä¸åº”出现直接访问 `install.spacetimedb.com` 或 OpenTelemetry GitHub release 下载地å€çš„回退日志。 - å…³è”æ–‡æ¡£ï¼š`docs/ã€å¼€å‘è¿ç»´ã€‘本地开å‘验è¯ä¸Žç”Ÿäº§è¿ç»´-2026-05-15.md`。 ## 2026-05-19 公开 gallery å…¥å£å‘å¸ƒé™æµä»¥å¿«æ‹’ç»ä¿æŠ¤åŽç«¯ diff --git a/.hermes/shared-memory/pitfalls.md b/.hermes/shared-memory/pitfalls.md index 46f4448f..cf2a4b9f 100644 --- a/.hermes/shared-memory/pitfalls.md +++ b/.hermes/shared-memory/pitfalls.md @@ -1032,6 +1032,14 @@ - 验è¯ï¼šæ£€æŸ¥ Jenkins build log 中是å¦å‡ºçް `[jenkins-powershell] user:` å’Œ `[jenkins-powershell] exe:`ï¼Œä»¥åŠ `[stdb-checkout] current HEAD:`。上游 Full Build 传下æ¥çš„ `COMMIT_HASH` è‹¥å·²ç­‰äºŽå½“å‰ GitSCM checkout,日志应显示 `requested commit already matches Jenkins GitSCM checkout` å¹¶ç»§ç»­è¿›å…¥æž„å»ºé˜¶æ®µï¼›åŒæ—¶ç¡®è®¤ `builds//log` ä¸å†åœåœ¨ `PipelineNodeTreeScanner... Cannot run program "powershell"` 或 Checkout 内部 exit code 5。 - å…³è”:`jenkins/Jenkinsfile.production-stdb-module-build`ã€`docs/ã€å¼€å‘è¿ç»´ã€‘本地开å‘验è¯ä¸Žç”Ÿäº§è¿ç»´-2026-05-15.md`。 +## Server-Provision Windows 下载 helper ä¸è¦åŽŸåœ°é‡å†™ä¸´æ—¶ ps1 + +- 现象:`Genarrative-Server-Provision` çš„ Windows ä¸‹è½½é˜¶æ®µå·²ç»æ‰“å°äº† `[jenkins-powershell] user:` å’Œ `[jenkins-powershell] exe:`,但在 `.ps1` 原地 BOM é‡å†™å‰åŽä»ç„¶è¿”回 `exit code 5` / `æ‹’ç»è®¿é—®`,且下载目录还没创建。 +- 原因:Jenkins `writeFile` 生æˆçš„临时 `.ps1` 正被åŒä¸€ä¸ª workspace 里的 PowerShell 进程马上é‡å†™æˆ BOM 文件,这个原地改写在本地 Windows Jenkins 环境里比直接脚本执行更容易碰到 workspace å ç”¨æˆ– ACL æ‹’ç»ã€‚å¯¹è¿™æ¡æµæ°´çº¿æ¥è¯´ï¼ŒBOM 䏿˜¯å¿…须的执行æ¡ä»¶ã€‚ +- 处ç†ï¼š`runWindowsPowerShell(...)` 改æˆå…ˆ `writeFile`,å†ç”±æ˜¾å¼ `powershell.exe` 读å–脚本文本并用 `ScriptBlock::Create(...)` 直接在内存中执行,ä¸å†å¯¹åŒä¸€ä¸ª `.ps1` åš BOM é‡å†™ã€‚Windows 下载脚本里先把 `PROVISION_DOWNLOADS_DIR` 归一到 workspace ç»å¯¹è·¯å¾„,并补 `Windows workspace` / `download dir` / `已创建下载目录` 三段日志,方便区分是路径问题还是下载问题。 +- 验è¯ï¼šJenkins log 应先出现 `[jenkins-powershell] workspace:`ã€`[jenkins-powershell] loaded bytes:`,å†å‡ºçް `[prepare-provision-downloads] Windows workspace:` å’Œ `[prepare-provision-downloads] 已创建下载目录:`;如果下载 URL æ•…æ„æŒ‡åˆ°ä¸å¯è¾¾åœ°å€ï¼Œåº”该åªåœ¨ `curl 下载失败` 处结æŸï¼Œè€Œä¸æ˜¯å¡åœ¨ BOM é‡å†™å‰ã€‚ +- å…³è”:`jenkins/Jenkinsfile.production-server-provision`ã€`docs/ã€å¼€å‘è¿ç»´ã€‘本地开å‘验è¯ä¸Žç”Ÿäº§è¿ç»´-2026-05-15.md`。 + ## QQ æµè§ˆå™¨å‘现页推èå°é¢å…¨ä¸æ˜¾ç¤ºå…ˆæŸ¥ aspect-ratio 兜底 - 现象:å‘现页的“推èâ€å­é¢‘é“作å“塿 ‡é¢˜ã€ä½œè€…å’Œæ•°æ®æ­£å¸¸ï¼Œä½†æ‰€æœ‰å°é¢å›¾ä¸æ˜¾ç¤ºï¼Œå¸¸è§äºŽ QQ æµè§ˆå™¨ / X5 等旧移动内核。 diff --git a/docs/ã€å¼€å‘è¿ç»´ã€‘本地开å‘验è¯ä¸Žç”Ÿäº§è¿ç»´-2026-05-15.md b/docs/ã€å¼€å‘è¿ç»´ã€‘本地开å‘验è¯ä¸Žç”Ÿäº§è¿ç»´-2026-05-15.md index be4285e1..8ed3324b 100644 --- a/docs/ã€å¼€å‘è¿ç»´ã€‘本地开å‘验è¯ä¸Žç”Ÿäº§è¿ç»´-2026-05-15.md +++ b/docs/ã€å¼€å‘è¿ç»´ã€‘本地开å‘验è¯ä¸Žç”Ÿäº§è¿ç»´-2026-05-15.md @@ -160,7 +160,7 @@ Windows Stdb module æž„å»ºæµæ°´çº¿è¿è¡Œåœ¨ Jenkins `windows` 节点上。该 - `api-server` 生产模æ¿é»˜è®¤ `GENARRATIVE_API_LISTEN_BACKLOG=1024`ã€`GENARRATIVE_API_WORKER_THREADS=4`;本地未设置 worker threads 时继续使用 Tokio 默认值。 - `GENARRATIVE_API_MAX_CONCURRENT_REQUESTS=512` å¼€å¯åº”用内 HTTP å¹¶å‘背压;`GENARRATIVE_API_GALLERY_MAX_CONCURRENT_REQUESTS=320`ã€`GENARRATIVE_API_DETAIL_MAX_CONCURRENT_REQUESTS=64`ã€`GENARRATIVE_API_ADMIN_MAX_CONCURRENT_REQUESTS=16` 分别é™åˆ¶å…¬å¼€åˆ—表ã€å…¬å¼€è¯¦æƒ…å’ŒåŽå° API çƒ­è·¯å¾„ã€‚è¶…è¿‡è®¸å¯æ—¶ç›´æŽ¥è¿”回 `429 Too Many Requests` å’Œ `Retry-After: 1`,`/healthz` ä¸å—该é™åˆ¶ã€‚è¿™äº›å€¼ä¸æ˜¯ RPS é™é€Ÿï¼›å¦‚果压测中 429 上å‡ä½†å†…存和 p95 æ”¶æ•›ï¼Œè¯´æ˜ŽèƒŒåŽ‹æ­£åœ¨ä¿æŠ¤è¿›ç¨‹ã€‚ç›´è¿ž `api-server` çš„æžé«˜ RPS 压测若出现 `connection refused`ï¼Œé€šå¸¸å·²ç»æ‰“到 TCP ç›‘å¬ / accept å±‚ï¼Œåº”åŒæ—¶æ£€æŸ¥ backlogã€Nginx upstream keepalive å’Œå‰ç½®é™æµã€‚ - `genarrative-api.service` 设置 `LimitNOFILE=65535`ã€`TasksMax=2048`;上线åŽç”¨ `systemctl show genarrative-api.service -p LimitNOFILE -p TasksMax` å’Œ `cat /proc/$(pidof api-server)/limits` 核对。 -- Server provision ä¸åœ¨ç›®æ ‡æœºè”网下载 SpacetimeDB 或 `otelcol-contrib`。`Genarrative-Server-Provision` 先在 Windows Jenkins 节点执行 `Download Provision Tool Archives`,把 `https://install.spacetimedb.com`ã€SpacetimeDB Linux update installer å’Œ `otelcol-contrib_0.151.0_linux_amd64.tar.gz` 先下载到工作区,å†é€šè¿‡ `stash/unstash` 带到 `genarrative-build-01`;目标 Linux 节点上的 `scripts/prepare-server-provision-tools.sh` åªæ¶ˆè´¹è¿™äº›æœ¬åœ°ä¸‹è½½ä»¶ç”Ÿæˆ `provision-tools/`,å†äº¤ç»™ `scripts/jenkins-server-provision.sh` 安装 `/stdb/spacetime`ã€`/stdb/bin/current/*` å’Œ `/usr/local/bin/otelcol-contrib`ã€‚æ³¨æ„ `scripts/jenkins-checkout-source.sh` 会执行 `git reset --hard` / `git clean`,因此被直接执行的新增脚本必须以 Git `100755` æ¨¡å¼æäº¤ï¼Œæˆ–åœ¨äºŒæ¬¡ checkout 之åŽå†è¡¥ `chmod +x`。 +- Server provision ä¸åœ¨ç›®æ ‡æœºè”网下载 SpacetimeDB 或 `otelcol-contrib`。`Genarrative-Server-Provision` 先在 Windows Jenkins 节点执行 `Download Provision Tool Archives`,把 `https://install.spacetimedb.com`ã€SpacetimeDB Linux update installer å’Œ `otelcol-contrib_0.151.0_linux_amd64.tar.gz` 先下载到工作区,å†é€šè¿‡ `stash/unstash` 带到 `genarrative-build-01`;目标 Linux 节点上的 `scripts/prepare-server-provision-tools.sh` åªæ¶ˆè´¹è¿™äº›æœ¬åœ°ä¸‹è½½ä»¶ç”Ÿæˆ `provision-tools/`,å†äº¤ç»™ `scripts/jenkins-server-provision.sh` 安装 `/stdb/spacetime`ã€`/stdb/bin/current/*` å’Œ `/usr/local/bin/otelcol-contrib`。Windows ä¾§çš„ `runWindowsPowerShell(...)` 现在会先 `writeFile` ç”Ÿæˆ UTF-8 `.ps1`,å†ç›´æŽ¥æŠŠè„šæœ¬æ–‡æœ¬è¯»å…¥å†…å­˜å¹¶é€šè¿‡ `ScriptBlock::Create(...)` 执行,é¿å…对åŒä¸€ä¸ª workspace 脚本åšåŽŸåœ° BOM é‡å†™ï¼›å› æ­¤æŽ’查时除了看下载日志,还è¦çœ‹ `[jenkins-powershell] workspace:`ã€`[jenkins-powershell] script:` å’Œ `[jenkins-powershell] loaded bytes:`ã€‚æ³¨æ„ `scripts/jenkins-checkout-source.sh` 会执行 `git reset --hard` / `git clean`,因此被直接执行的新增脚本必须以 Git `100755` æ¨¡å¼æäº¤ï¼Œæˆ–åœ¨äºŒæ¬¡ checkout 之åŽå†è¡¥ `chmod +x`。 - Windows 下载阶段如果走代ç†ï¼Œåœ¨ `Genarrative-Server-Provision` 傿•° `PROVISION_DOWNLOAD_PROXY` 填写 Windows Jenkins 节点å¯è®¿é—®çš„ HTTP 代ç†ï¼Œä¾‹å¦‚ `http://127.0.0.1:7890`ï¼›ä¸è¦å¡«å†™ç›®æ ‡ release 机器视角的 `127.0.0.1`,除éžä»£ç†ç¡®å®žè¿è¡Œåœ¨è¯¥ Windows 节点本机。Linux ç›®æ ‡æœºé˜¶æ®µä¼šå¼ºåˆ¶è¦æ±‚使用本地下载件,缺少文件直接失败,ä¸å†å›žé€€åˆ°å¤–网下载。 - `otelcol-contrib.service` 作为å¯é€‰ç³»ç»ŸæœåŠ¡åŠ å…¥ provisionï¼Œé»˜è®¤ç›‘å¬ `127.0.0.1:4317/4318` 并使用 `deploy/otelcol/genarrative-debug.yaml`。api-server 是å¦å‘é€ OTLP ä»ç”± `GENARRATIVE_OTEL_ENABLED` 控制,æœåŠ¡ unit è§ `deploy/systemd/otelcol-contrib.service`。 - Nginx `/api/` 与 `/admin/api/` 通过 `genarrative_api` upstream 代ç†åˆ° `127.0.0.1:8082`,upstream keepalive 为 64ï¼›`limit_conn` 负责连接 / å¹¶å‘ä¿æŠ¤ï¼Œ`limit_req` è´Ÿè´£å…¥å£ RPS å¿«æ‹’ç»ã€‚当剿¨¡æ¿æŠŠå…¬å¼€ gallery list å•独放到 `genarrative_gallery_rps`,默认 `rate=5000r/s`ã€`burst=4096`ã€`limit_conn=320`;公开详情和普通 API 放到 `genarrative_api_rps`,åŽå° API 放到 `genarrative_admin_rps`。压测时看 `/var/log/nginx/genarrative.access.log` 中的 `request_time`ã€`upstream_connect_time`ã€`upstream_header_time`ã€`upstream_response_time`ã€`upstream_status`ã€`request_id`。 diff --git a/jenkins/Jenkinsfile.production-server-provision b/jenkins/Jenkinsfile.production-server-provision index c324b3e0..e95ef581 100644 --- a/jenkins/Jenkinsfile.production-server-provision +++ b/jenkins/Jenkinsfile.production-server-provision @@ -11,10 +11,13 @@ if not exist "%GENARRATIVE_POWERSHELL%" ( ) echo [jenkins-powershell] user: whoami +echo [jenkins-powershell] workspace: %CD% echo [jenkins-powershell] exe: %GENARRATIVE_POWERSHELL% -"%GENARRATIVE_POWERSHELL%" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "\$path = '%CD%\\${scriptPath}'; \$text = [System.IO.File]::ReadAllText(\$path, [System.Text.Encoding]::UTF8); \$utf8Bom = New-Object System.Text.UTF8Encoding(\$true); [System.IO.File]::WriteAllText(\$path, \$text, \$utf8Bom)" -if errorlevel 1 exit /b %ERRORLEVEL% -"%GENARRATIVE_POWERSHELL%" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%CD%\\${scriptPath}" +if not exist "%CD%\\${scriptPath}" ( + echo [jenkins-powershell] script not found: %CD%\\${scriptPath} + exit /b 1 +) +"%GENARRATIVE_POWERSHELL%" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "try { \$path = Join-Path (Get-Location).ProviderPath '${scriptPath}'; Write-Host '[jenkins-powershell] script:' \$path; \$text = [System.IO.File]::ReadAllText(\$path, [System.Text.Encoding]::UTF8); Write-Host '[jenkins-powershell] loaded bytes:' ([System.IO.File]::ReadAllBytes(\$path).Length); \$scriptBlock = [ScriptBlock]::Create(\$text); & \$scriptBlock; if (\$LASTEXITCODE -is [int] -and \$LASTEXITCODE -ne 0) { exit \$LASTEXITCODE } } catch { Write-Host '[jenkins-powershell] failed:' \$_.Exception.Message; if (\$_.ScriptStackTrace) { Write-Host \$_.ScriptStackTrace }; exit 1 }" exit /b %ERRORLEVEL% """ } @@ -153,11 +156,20 @@ pipeline { $spacetimeDownloadRoot = if ($env:SPACETIME_DOWNLOAD_ROOT) { $env:SPACETIME_DOWNLOAD_ROOT.TrimEnd('/') } else { 'https://github.com/clockworklabs/SpacetimeDB/releases/latest/download' } $spacetimeTargetHost = if ($env:SPACETIME_TARGET_HOST) { $env:SPACETIME_TARGET_HOST } else { 'x86_64-unknown-linux-gnu' } $downloadProxy = if ($env:PROVISION_DOWNLOAD_PROXY) { $env:PROVISION_DOWNLOAD_PROXY } else { '' } + $workspace = (Get-Location).ProviderPath + if ([System.IO.Path]::IsPathRooted($downloadsDir)) { + throw "[prepare-provision-downloads] PROVISION_DOWNLOADS_DIR åªèƒ½æ˜¯å·¥ä½œåŒºå†…相对路径: ${downloadsDir}" + } + $downloadsDir = Join-Path $workspace $downloadsDir + Write-Host "[prepare-provision-downloads] Windows workspace: ${workspace}" + Write-Host "[prepare-provision-downloads] download dir: ${downloadsDir}" if (Test-Path -LiteralPath $downloadsDir) { + Write-Host "[prepare-provision-downloads] æ¸…ç†æ—§ä¸‹è½½ç›®å½•: ${downloadsDir}" Remove-Item -LiteralPath $downloadsDir -Recurse -Force } New-Item -ItemType Directory -Force -Path $downloadsDir | Out-Null + Write-Host "[prepare-provision-downloads] 已创建下载目录: ${downloadsDir}" if ($downloadProxy) { $env:HTTP_PROXY = $downloadProxy