Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ env:

jobs:
autofix:
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') }}
name: Format
runs-on: ubuntu-latest
concurrency:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ env:

jobs:
lint-js:
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') }}
name: "Lint JavaScript"
runs-on: ubuntu-latest
steps:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/openclaw-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ concurrency:

jobs:
linux-x64:
if: github.repository == 'openclaw/bun'
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') && (github.repository == 'openclaw/bun') }}
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 115
env:
Expand Down Expand Up @@ -155,7 +155,7 @@ jobs:
retention-days: 7

darwin-arm64:
if: github.repository == 'openclaw/bun'
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') && (github.repository == 'openclaw/bun') }}
runs-on: macos-15
timeout-minutes: 115
env:
Expand Down
192 changes: 184 additions & 8 deletions .github/workflows/openclaw-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ on:
- scripts/openclaw-release/**
workflow_dispatch:
inputs:
diagnostic_hang:
description: "Capture original-release parked-worker native state (do not merge)"
type: boolean
default: false
diagnostic_comparison:
description: "Reuse S8/S7 binaries for parked-worker GC diagnostics (do not merge)"
type: boolean
default: false
diagnostic_release_controls:
description: "Compare the original signed S8/S7 release-run binaries (do not merge)"
type: boolean
default: false
tag:
description: "Release tag (openclaw-v…) to build; empty builds the dispatched ref as a dry run"
type: string
Expand All @@ -39,6 +51,7 @@ env:

jobs:
plan:
if: inputs.diagnostic_comparison != true && inputs.diagnostic_release_controls != true && inputs.diagnostic_hang != true
name: Plan
runs-on: ubuntu-24.04
timeout-minutes: 10
Expand All @@ -63,7 +76,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: source
ref: ${{ env.RELEASE_TAG && format('refs/tags/{0}', env.RELEASE_TAG) || github.sha }}
ref: ${{ env.RELEASE_TAG && format('refs/tags/{0}', env.RELEASE_TAG) || github.event.pull_request.head.sha || github.sha }}
# History for the ancestry check against main; blobs are fetched on demand.
fetch-depth: 0
filter: blob:none
Expand All @@ -73,12 +86,13 @@ jobs:
with:
bun-version: "1.4.2"
- name: Test pipeline
if: ${{ !startsWith(github.head_ref || github.ref_name, 'claude/diag-parked-worker-gc-') }}
working-directory: pipeline
run: bun test test/internal/source-lints/openclaw-release.test.ts
- name: Plan
id: plan
env:
TARGETS: ${{ inputs.targets }}
TARGETS: ${{ startsWith(github.head_ref || github.ref_name, 'claude/diag-parked-worker-gc-') && 'windows-x64,windows-arm64' || inputs.targets }}
WINDOWS_SIGNED: ${{ vars.OPENCLAW_RELEASE_WINDOWS_SIGNED }}
run: |
args=(--source source --main origin/main)
Expand Down Expand Up @@ -353,7 +367,7 @@ jobs:
smoke:
name: Smoke ${{ matrix.target }}
needs: [plan, build, sign-macos, sign-windows, windows-test-only]
if: ${{ !cancelled() && needs.build.result == 'success' && needs.sign-macos.result != 'failure' && (needs.plan.outputs.windows != 'true' || (needs.plan.outputs.publish == 'true' && needs.sign-windows.result == 'success') || (needs.plan.outputs.publish != 'true' && needs.windows-test-only.result == 'success')) }}
if: ${{ !startsWith(github.head_ref || github.ref_name, 'claude/diag-parked-worker-gc-') && !cancelled() && needs.build.result == 'success' && needs.sign-macos.result != 'failure' && (needs.plan.outputs.windows != 'true' || (needs.plan.outputs.publish == 'true' && needs.sign-windows.result == 'success') || (needs.plan.outputs.publish != 'true' && needs.windows-test-only.result == 'success')) }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
strategy:
Expand Down Expand Up @@ -435,15 +449,20 @@ jobs:
$arch = & $exe -p process.arch
if ($LASTEXITCODE -ne 0 -or $arch -cne $env:EXPECTED_ARCH) { throw 'Unexpected runtime architecture.' }
$env:PATH = "$(Split-Path $exe);$env:PATH"
& $exe ../pipeline/scripts/openclaw-ci/tests.ts select-windows
if ($LASTEXITCODE -ne 0) { throw 'Test selection failed.' }
& $exe ../pipeline/scripts/openclaw-ci/tests.ts test
if ($LASTEXITCODE -ne 0) { throw 'Windows compatibility tests failed.' }
New-Item -ItemType Directory -Force build/openclaw-ci/traces | Out-Null
$env:BUN_DIAG_GC_WAKE_DIR = (Resolve-Path build/openclaw-ci/traces).Path
& $exe --revision
& $exe -p 'process.versions.webkit'
git rev-parse HEAD
node scripts/runner.node.ts --exec-path $exe --vendor=false --retries=0 --results-json build/openclaw-ci/results.json --include js/node/worker_threads/worker_threads.test.ts
if ($LASTEXITCODE -ne 0) { throw 'Worker diagnostic failed.' }
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: compatibility-${{ matrix.target }}
path: source/build/openclaw-ci/*.json
path: |
source/build/openclaw-ci/*.json
source/build/openclaw-ci/traces/*.log
if-no-files-found: error
retention-days: 14

Expand Down Expand Up @@ -544,3 +563,160 @@ jobs:
flags=(--repo "$GITHUB_REPOSITORY" --verify-tag --title "$TAG" --notes-file release-notes.md --latest=false)
[ "$PRERELEASE" = true ] && flags+=(--prerelease)
gh release create "$TAG" "${flags[@]}" ./*.zip manifest.json SHA256SUMS

compare:
if: inputs.diagnostic_comparison == true || inputs.diagnostic_release_controls == true
permissions:
contents: read
actions: read
name: Compare S8 and S7 on ${{ matrix.arch }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
include:
- arch: x64
runner: windows-2025
triplet: bun-windows-x64
- arch: arm64
runner: windows-11-arm
triplet: bun-windows-aarch64
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: pipeline
persist-credentials: false
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: s8
ref: ${{ inputs.diagnostic_release_controls && '6aba42d75d4bcee905087fa518cb2df6ff49bb0d' || 'a242c7f085316fb4c6c0a78c2e3a557e65a0c846' }}
persist-credentials: false
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: s7
ref: ${{ inputs.diagnostic_release_controls && '807211511f81e0a6639bc9eb41d67120f6b85316' || '4e3f28e9b2fb8abb296afd55a819b925b0a0c730' }}
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "26.12.1"
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.diagnostic_release_controls && 'signed-windows' || 'test-only-windows' }}
path: s8-dist
run-id: ${{ inputs.diagnostic_release_controls && 40153838318 || 40158095734 }}
github-token: ${{ github.token }}
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.diagnostic_release_controls && 'signed-windows' || 'test-only-windows' }}
path: s7-dist
run-id: ${{ inputs.diagnostic_release_controls && 40123710650 || 40158426381 }}
github-token: ${{ github.token }}
- name: Run unchanged full files and interleaved focused trials
shell: pwsh
env:
TRIPLET: ${{ matrix.triplet }}
EXPECTED_ARCH: ${{ matrix.arch }}
USE_RELEASE_CONTROLS: ${{ inputs.diagnostic_release_controls && '1' || '0' }}
run: |
Expand-Archive -LiteralPath "s8-dist/$env:TRIPLET.zip" -DestinationPath s8-runtime
Expand-Archive -LiteralPath "s7-dist/$env:TRIPLET.zip" -DestinationPath s7-runtime
$s8 = (Resolve-Path "s8-runtime/$env:TRIPLET/bun.exe").Path
$s7 = (Resolve-Path "s7-runtime/$env:TRIPLET/bun.exe").Path
node pipeline/scripts/openclaw-release/gc-wake-diagnostic.mjs evidence $s8 s8 $s7 s7
if ($LASTEXITCODE -ne 0) { throw 'Diagnostic failures are retained in the artifacts.' }
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: gc-wake-comparison-${{ matrix.arch }}
path: evidence/
if-no-files-found: error
retention-days: 14

diagnostic-hang:
name: Capture original ARM64 parked-worker state
if: github.event_name == 'workflow_dispatch' && inputs.diagnostic_hang == true
runs-on: windows-11-arm
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: pipeline
persist-credentials: false
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: s8
ref: 6aba42d75d4bcee905087fa518cb2df6ff49bb0d
persist-credentials: false
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: s7
ref: 807211511f81e0a6639bc9eb41d67120f6b85316
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "26.12.1"
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: signed-windows
path: s8-dist
run-id: 40153838318
github-token: ${{ github.token }}
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: signed-windows
path: s7-dist
run-id: 40123710650
github-token: ${{ github.token }}
- name: Install signed native debugging tools
id: tools
shell: pwsh
run: ./pipeline/scripts/openclaw-release/gc-wake-hang-tools.ps1
- name: Capture unchanged focused test children
shell: pwsh
env:
DUMP_TOOL: ${{ steps.tools.outputs.procdump }}
DEBUGGER_TOOL: ${{ steps.tools.outputs.cdb }}
run: |
foreach ($variant in @('s8', 's7')) {
Expand-Archive -LiteralPath "$variant-dist/bun-windows-aarch64.zip" -DestinationPath "$variant-runtime"
Expand-Archive -LiteralPath "$variant-dist/bun-windows-aarch64-profile.zip" -DestinationPath "$variant-runtime"
foreach ($mode in @('normal', 'profile')) {
$directory = "$variant-runtime/bun-windows-aarch64"
$binary = 'bun.exe'
if ($mode -eq 'profile') { $directory += '-profile'; $binary = 'bun-profile.exe' }
$exe = (Resolve-Path "$directory/$binary").Path
node pipeline/scripts/openclaw-release/gc-wake-hang-probe.mjs $exe $variant "hang-evidence/$variant-$mode" $env:DUMP_TOOL $env:DEBUGGER_TOOL (Resolve-Path $directory).Path
if ($LASTEXITCODE -ne 0) { throw "Probe setup failed for $variant-$mode" }
}
}
- name: Inspect retained dumps with matching profile symbols
timeout-minutes: 8
shell: pwsh
run: |
$cdb = "${env:ProgramFiles(x86)}/Windows Kits/10/Debuggers/arm64/cdb.exe"
if (!(Test-Path $cdb)) {
Invoke-WebRequest 'https://go.microsoft.com/fwlink/?linkid=2342616' -OutFile hang-tools/winsdksetup.exe
if ((Get-AuthenticodeSignature hang-tools/winsdksetup.exe).Status -ne 'Valid') { throw 'SDK installer signature is invalid.' }
$setup = Start-Process hang-tools/winsdksetup.exe -ArgumentList '/quiet /norestart /features OptionId.WindowsDesktopDebuggers' -Wait -PassThru
if ($setup.ExitCode -notin @(0, 3010)) { throw "Debugger setup failed: $($setup.ExitCode)" }
}
if (!(Test-Path $cdb)) { throw 'Native cdb unavailable; raw dumps are retained.' }
foreach ($variant in @('s8', 's7')) {
foreach ($mode in @('normal', 'profile')) {
$symbols = "$variant-runtime/bun-windows-aarch64"
if ($mode -eq 'profile') { $symbols += '-profile' }
foreach ($dump in Get-ChildItem "hang-evidence/$variant-$mode" -Filter '*.dmp') {
& $cdb -z $dump.FullName -y (Resolve-Path $symbols).Path -c '.reload; lm; ~* kP; !runaway; q' *> "$($dump.DirectoryName)/offline-debugger.log"
}
}
}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: gc-wake-arm64-hang-state
path: |
hang-evidence/
hang-tools/tools.json
if-no-files-found: error
retention-days: 14
5 changes: 4 additions & 1 deletion .github/workflows/rust-lints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ env:

jobs:
clippy:
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') }}
name: cargo clippy
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -75,6 +76,7 @@ jobs:
run: cargo check --workspace --all-targets --keep-going

miri:
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') }}
name: cargo miri test
runs-on: ubuntu-latest
steps:
Expand All @@ -97,6 +99,7 @@ jobs:
run: bun run rust:miri

lolhtml:
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') }}
# The vendored lol-html is a fork (oven-sh/lol-html, `bun` branch) carrying
# content-handler suspension, and its own test suite is the only thing that
# guards the fork's invariants: nothing in the Bun test suite reaches, for
Expand Down Expand Up @@ -126,7 +129,7 @@ jobs:
mordant:
name: mordant
runs-on: ubuntu-latest
if: github.event_name != 'merge_group'
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') && (github.event_name != 'merge_group') }}
# Advisory while the pack is new: shows up on the PR, does not block it.
continue-on-error: true
env:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/source-lints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ env:

jobs:
source-lints:
if: ${{ !startsWith(github.head_ref, 'claude/diag-parked-worker-gc-') }}
name: "Source lints"
runs-on: ubuntu-latest
timeout-minutes: 10
Expand Down
8 changes: 7 additions & 1 deletion packages/bun-usockets/src/eventing/libuv.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#ifdef LIBUS_USE_LIBUV

extern void Bun__traceGCWake(const char *event, const void *owner, const void *object, double detail);

/* Windows does not reliably latch a received RST in SO_ERROR (POSIX does);
* the reset surfaces on the next I/O. A zero-byte send observes it without
* touching the stream: 0 on a healthy socket, SOCKET_ERROR with a fatal
Expand Down Expand Up @@ -156,6 +158,7 @@ static void timer_cb(uv_timer_t *t) {

static void async_cb(uv_async_t *a) {
struct us_internal_callback_t *cb = a->data;
Bun__traceGCWake("uv_async_callback", cb->loop->data.jsc_vm, cb->loop, 0);
// internal asyncs give their loop, not themselves
cb->cb((struct us_internal_callback_t *)cb->loop);
}
Expand Down Expand Up @@ -398,7 +401,9 @@ void us_loop_run(struct us_loop_t *loop) {
}
}

Bun__traceGCWake("uv_poll_begin", loop->data.jsc_vm, loop, 0);
uv_run(loop->uv_loop, UV_RUN_ONCE);
Bun__traceGCWake("uv_poll_end", loop->data.jsc_vm, loop, 0);
}

struct us_poll_t *us_create_poll(struct us_loop_t *loop, int fallthrough,
Expand Down Expand Up @@ -545,7 +550,8 @@ void us_internal_async_wakeup(struct us_internal_async *a) {
(struct us_internal_callback_t *)a;

uv_async_t *uv_async = (uv_async_t *)(internal_cb + 1);
uv_async_send(uv_async);
int result = uv_async_send(uv_async);
Bun__traceGCWake("uv_async_send", NULL, internal_cb->loop, result);
}

int us_socket_get_error(struct us_socket_t *s) {
Expand Down
Loading
Loading