Skip to content
Merged
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
22 changes: 17 additions & 5 deletions .github/OPENCLAW_CI.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,20 @@ attempts. These are build-step times, excluding provisioning and artifact upload

The first test attempt failed `compile cache wakes an idle loop for deferred
modules` in `test/js/node/module/node-module-module.test.js` with `idle
persistence stalled`; the unchanged rerun passed every selected file. Keep
this intermittent failure visible: the lane has no automatic test retries or
exclusion for it. Investigate idle persistence separately if it recurs; a
green rerun does not establish the cause. Artifact names include the run
attempt so a download cannot confuse an earlier failed report with a later one.
persistence stalled`. [PR #53](https://github.com/openclaw/bun/pull/53) fixed
that Linux idle-accounting bug: a poll following a consumed native wake could
block without counting its wait as idle.

Windows x64 [run 37340737589](https://github.com/openclaw/bun/actions/runs/37340737589)
later hit the outer 30-second deadlines in both cache-exit and deferred-idle
tests. The same failure reproduces with continuous cache-file progress under
Microsoft Defender. The Windows rename helper requested `FILE_TRAVERSE`, which
is `FILE_EXECUTE` for a regular file, forcing synchronous executable-file scans
for each cache entry. The helper now uses its existing non-executable access
rights directly. The test workloads, deadlines, idle-generation window, and
signal-exit budget are unchanged.

Keep later failures distinguishable from these causes; a green rerun does not
establish a cause. The native lane has no automatic test retries or exclusion
for this file. Artifact names include the run attempt so a download cannot
confuse an earlier failed report with a later one.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,5 @@
- Account for typed-array and ArrayBuffer payloads before GC, preserve allocation-origin charges across worker transfers, separate external storage from JS heap statistics, and answer worker heap-statistics requests during JavaScript loops and atomic waits. Builds on oven-sh/bun#34406 and oven-sh/WebKit#303; thanks @robobun.

- Publish Darwin/Linux prereleases while Windows signing is unconfigured; require an explicit signed-Windows release switch before including either Windows architecture, while preserving test-only Windows CI.

- Avoid requesting executable access when renaming files on Windows, preventing unnecessary synchronous antivirus scans during compile-cache publication.
2 changes: 1 addition & 1 deletion docs/runtime/nodejs-compat.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ Package imports and exports match the `module-sync` condition for both `import`

`NODE_COMPILE_CACHE` and `module.enableCompileCache()` generate and atomically write cache entries during idle time. Normal exits wait for pending cache work. After a native SIGTERM, SIGINT, or SIGHUP, Bun limits automatic exit-time cache waiting to 250 ms, including when JavaScript handled the signal. Unfinished entries compile normally on the next run. Explicit `module.flushCompileCache()` calls always wait for persistence to finish. Standalone executables ignore `NODE_COMPILE_CACHE`.

Deferred cache generation continues on idle event loops even after JavaScript timers are removed. Its native wakeups do not keep the process alive.
Deferred cache generation continues on idle event loops even after JavaScript timers are removed. Its native wakeups do not keep the process alive. Windows cache publication avoids requesting executable access to cache data files, which can otherwise trigger synchronous antivirus scans.

### [`node:net`](https://nodejs.org/api/net.html)

Expand Down
45 changes: 11 additions & 34 deletions src/sys/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1895,40 +1895,17 @@ pub(crate) fn rename_at_w(
new_path_w: &[u16],
replace_if_exists: bool,
) -> bun_sys::Result<()> {
let src_fd = 'brk: {
match bun_sys::open_file_at_windows(
old_dir_fd,
old_path_w,
bun_sys::NtCreateFileOptions {
access_mask: win32::SYNCHRONIZE
| win32::GENERIC_WRITE
| win32::DELETE
| win32::FILE_TRAVERSE,
disposition: win32::FILE_OPEN,
options: win32::FILE_SYNCHRONOUS_IO_NONALERT | win32::FILE_OPEN_REPARSE_POINT,
..Default::default()
},
) {
bun_sys::Result::Err(_) => {
// retry, wtihout FILE_TRAVERSE flag
match bun_sys::open_file_at_windows(
old_dir_fd,
old_path_w,
bun_sys::NtCreateFileOptions {
access_mask: win32::SYNCHRONIZE | win32::GENERIC_WRITE | win32::DELETE,
disposition: win32::FILE_OPEN,
options: win32::FILE_SYNCHRONOUS_IO_NONALERT
| win32::FILE_OPEN_REPARSE_POINT,
..Default::default()
},
) {
bun_sys::Result::Err(err2) => return bun_sys::Result::Err(err2),
bun_sys::Result::Ok(fd) => break 'brk fd,
}
}
bun_sys::Result::Ok(fd) => break 'brk fd,
}
};
// FILE_TRAVERSE is FILE_EXECUTE for files and can force synchronous antivirus scans.
let src_fd = bun_sys::open_file_at_windows(
old_dir_fd,
old_path_w,
bun_sys::NtCreateFileOptions {
access_mask: win32::SYNCHRONIZE | win32::GENERIC_WRITE | win32::DELETE,
disposition: win32::FILE_OPEN,
options: win32::FILE_SYNCHRONOUS_IO_NONALERT | win32::FILE_OPEN_REPARSE_POINT,
..Default::default()
},
)?;
let _close = bun_sys::CloseOnDrop::new(src_fd);

move_opened_file_at(src_fd, new_dir_fd, new_path_w, replace_if_exists)
Expand Down
4 changes: 3 additions & 1 deletion test/js/node/module/node-module-module.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,9 @@ console.log("survived", require("./late.js"));`,
previous = current;
deadline = Date.now() + 10_000;
}
if (Date.now() >= deadline || proc.exitCode !== null) throw new Error("idle persistence stalled");
if (Date.now() >= deadline || proc.exitCode !== null) {
throw new Error(`idle persistence stalled at ${current}/${minimum} entries (exitCode: ${proc.exitCode})`);
}
await Bun.sleep(10);
}
};
Expand Down
Loading