Skip to content

fix(tools): address follow-up review comments from #9533 - #9553

Merged
quirogas merged 2 commits into
googleapis:mainfrom
danieljbruce:fix/bun-shim-follow-up-comments
Oct 7, 2026
Merged

quirogas merged 2 commits into
googleapis:mainfrom
danieljbruce:fix/bun-shim-follow-up-comments

Conversation

@danieljbruce

Copy link
Copy Markdown
Contributor

Description

Addresses all 7 follow-up review comments from #9533 in the Bun test shim and package test scripts.

Impact

Improves environment variable consistency, avoids unnecessary Proxy wrapping of require.cache for packages that only use --proxyquire-shim, prevents TypeError: globalThis.__googleCloudBunFetch is not a function when --bun-plugin-shim or --gaxios-shim is enabled without --fetch-shim, enables standalone execution of Spanner's observability-test under Bun, and removes the temporary full-suite CI trigger comment from ci/run_conditional_tests.sh.

Changes

  • Check both BUN_ENABLE_<NAME>_SHIM === 'true' and BUN_<NAME>_SHIM === 'true' in bin/proxyquire-bun-shim.cjs so the short environment variable names also work when Mocha is invoked directly without bin/run-test.cjs.
  • Gate the createCacheGeneration Proxy on Module._cache and require.cache under enableRequireShim instead of enableProxyquireShim, since only mockery in handwritten/storage reassigns Module._cache = ....
  • Update the AbortSignal.timeout comment in bin/proxyquire-bun-shim.cjs to reference core/packages/gaxios instead of core/packages/gcp-metadata.
  • Initialize globalThis.__googleCloudBunFetch whenever enableFetchShim || enableBunPluginShim || enableGaxiosShim is true (keeping the teeny-request Module._extensions['.js'] hook gated under enableFetchShim), and indent the body of globalThis.__googleCloudBunFetch by 2 spaces.
  • Add --proxyquire-shim to the observability-test script in handwritten/spanner/package.json.
  • Remove the temporary full-suite CI trigger comment from ci/run_conditional_tests.sh.

Testing

  • Verified in Bun that BUN_<NAME>_SHIM=true environment variables activate their respective shims when loading bin/proxyquire-bun-shim.cjs directly.
  • Verified in Bun that globalThis.__googleCloudBunFetch is defined when either BUN_GAXIOS_SHIM=true or BUN_PLUGIN_SHIM=true is enabled without BUN_FETCH_SHIM=true.
  • Verified in Bun that Module._cache / require.cache generational cache proxying is enabled under BUN_REQUIRE_SHIM=true.

Alternatives

  • We considered removing mockery from handwritten/storage/test/resumable-upload.ts instead of gating createCacheGeneration under enableRequireShim, but gating createCacheGeneration under enableRequireShim avoids modifying storage test dependencies while still eliminating the require.cache Proxy for the other 13 --proxyquire-shim packages.
  • Not merging this PR would leave --bun-plugin-shim and --gaxios-shim dependent on --fetch-shim being passed simultaneously and would cause every subsequent PR to run all 5 CI unit test shards due to the trigger comment in ci/run_conditional_tests.sh.

Fixes b/571038362

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the Bun shim configuration in bin/proxyquire-bun-shim.cjs to support shorter environment variable aliases, switches generational cache management to use enableRequireShim, and refactors the fetch interception logic to activate under multiple shim flags. Additionally, --proxyquire-shim is added to the Spanner observability tests. The review feedback highlights two important issues in the fetch shim: a potential infinite recursion/stack overflow if globalThis.fetch is reassigned to the shimmed fetch, and a memory leak caused by not removing the 'abort' event listener from init.signal once a request completes.

Comment thread bin/proxyquire-bun-shim.cjs Outdated
init = {...init, body: Readable.toWeb(stream)};
}
try {
const res = await globalThis.fetch(url, init);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If globalThis.fetch is ever reassigned to globalThis.__googleCloudBunFetch (for example, by another shim or plugin to globally apply the fetch interception), calling globalThis.fetch(url, init) here will cause infinite recursion and a stack overflow, because globalThis.fetch === origFetch will be false, bypassing the interception block and falling back to calling itself.

To prevent this, we should fall back to origFetch if globalThis.fetch is globalThis.__googleCloudBunFetch.

        const res = await (globalThis.fetch === globalThis.__googleCloudBunFetch ? origFetch : globalThis.fetch)(url, init);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 741191f — updated the HTTP/HTTPS transport check and the fallback call to use origFetch if globalThis.fetch === globalThis.__googleCloudBunFetch, preventing infinite recursion.

Comment thread bin/proxyquire-bun-shim.cjs Outdated
Comment on lines +566 to +572
init.signal.addEventListener('abort', () => {
req.destroy(
Object.assign(new Error('The user aborted a request.'), {
name: 'AbortError',
}),
);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The 'abort' event listener is added to init.signal but is never removed when the request completes successfully or fails. If init.signal is a long-lived AbortSignal (which is common when reused across multiple requests), this will cause a memory leak and may trigger a MaxListenersExceededWarning in Node.js/Bun.

We should define a named listener and remove it when the request finishes or errors using the request's 'close' event.

              const abortHandler = () => {
                req.destroy(
                  Object.assign(new Error('The user aborted a request.'), {
                    name: 'AbortError',
                  }),
                );
              };
              init.signal.addEventListener('abort', abortHandler);
              req.on('close', () => {
                init.signal.removeEventListener('abort', abortHandler);
              });

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 741191f — added a named abortHandler with {once: true} and removed it on the request's 'close' event to avoid leaking listeners on long-lived AbortSignals.

@danieljbruce
danieljbruce marked this pull request as ready for review October 7, 2026 19:49
@danieljbruce
danieljbruce requested review from a team as code owners October 7, 2026 19:49
@github-actions
github-actions Bot requested a review from shivanee-p October 7, 2026 19:50
@quirogas
quirogas merged commit 901a99b into googleapis:main Oct 7, 2026
75 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants