Skip to content

Pre-install the JavaScript RPC npm package before running tests - #956

Merged
timtebeek merged 1 commit into
mainfrom
tim/los-angeles-v2
Jul 31, 2026
Merged

Pre-install the JavaScript RPC npm package before running tests#956
timtebeek merged 1 commit into
mainfrom
tim/los-angeles-v2

Conversation

@timtebeek

@timtebeek timtebeek commented Jul 30, 2026

Copy link
Copy Markdown
Member

What's changed

test now depends on a warmJavaScriptRpcCache task that runs npx --yes --package=@openrewrite/rewrite@<version> rewrite-rpc once, using the version embedded in the resolved rewrite-javascript jar.

Why

CI has been failing intermittently for weeks with ~9 TypeScript tests reporting RPC process shut down early with exit code 1 (also 127 and 217, varying within a single run) — see run 30564235862, and previously 2026-07-15, 07-16, 07-19 and 07-28. It never reproduced locally.

JavaScriptRewriteRpc spawns npx --package=@openrewrite/rewrite@<version> rewrite-rpc, and the RPC process is shut down between test classes. Shimming npx on a runner showed four overlapping invocations in seven seconds, each triggering its own npm warn exec The following package was not found and will be installed, none of them reaching an exit:

=== 17:54:41.318702951 pid=3015 argv: --package=@openrewrite/rewrite@8.89.0-20260730-165737 rewrite-rpc
=== 17:54:44.022766233 pid=3053 argv: --package=@openrewrite/rewrite@8.89.0-20260730-165737 rewrite-rpc
=== 17:54:47.525195532 pid=3079 argv: --package=@openrewrite/rewrite@8.89.0-20260730-165737 rewrite-rpc
=== 17:54:48.681182317 pid=3097 argv: --package=@openrewrite/rewrite@8.89.0-20260730-165737 rewrite-rpc

An install takes ~3s, so on a cold cache these overlap in the same ~/.npm/_npx/<hash> directory and leave it half-written — one symptom being sh: 1: rewrite-rpc: Permission denied (exit 127) from a bin symlink whose target has not been chmod'ed yet. Locally the cache is always warm, so the install never happens and the race never opens.

Testing

On a clean ubuntu-latest runner, running the nine TypeScript test classes:

  • without this change: all nine fail
  • with this change: all nine pass

Follow-up

The TypeScript tests spawn `npx --package=@openrewrite/rewrite@<version> rewrite-rpc`,
and the RPC process is shut down between test classes. On a cold npx cache each spawn
starts its own install into the same `~/.npm/_npx` directory; the overlapping installs
leave the package half-written and the tests fail with "RPC process shut down early with
exit code 1/127/217".

Installing the package once before `test` keeps every spawn a cache hit. Verified on a
clean runner: all nine TypeScript test classes fail without this change and pass with it.
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Jul 30, 2026
@timtebeek
timtebeek merged commit 968ce84 into main Jul 31, 2026
1 check passed
@timtebeek
timtebeek deleted the tim/los-angeles-v2 branch July 31, 2026 08:09
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Jul 31, 2026
timtebeek added a commit that referenced this pull request Aug 11, 2026
Three gaps in warmJavaScriptRpcCache as it landed in #956, all verified
against Gradle 9.3.1.

The marker was written unconditionally, so an install that failed once was
cached as done until the jar version changed — the flake comes back with the
warning long gone. Writing it only on success is necessary but not sufficient:
Gradle counts a declared output that was absent last time and is absent now as
up to date, and skips the task anyway. So ask explicitly whether the marker
exists, and delete it before each attempt. Fail, fail again (re-runs), succeed,
then UP-TO-DATE.

`isIgnoreExitValue` covers a process that exits non-zero, not one that never
starts, so an absent npx failed the build outright with "A problem occurred
starting process 'command 'npx''" — and because every Test task depends on
this, `./gradlew test` died there before running a single test on a machine
without Node. Catch it and warn, like the other failures here.

A locally built rewrite-javascript, which mavenLocal makes it easy to pick up,
reports `-SNAPSHOT` rather than a timestamped npm version and spawns an
`npm link`ed rewrite-rpc from its working copy. There is no published package
to install, so the attempt only bought a 404 and a misleading warning.
mergify Bot added a commit to robfrank/linklift that referenced this pull request Aug 20, 2026
… 2.40.0 to 2.41.0 [skip ci]

Bumps [org.openrewrite.recipe:rewrite-static-analysis](https://github.com/openrewrite/rewrite-static-analysis) from 2.40.0 to 2.41.0.
Release notes

*Sourced from [org.openrewrite.recipe:rewrite-static-analysis's releases](https://github.com/openrewrite/rewrite-static-analysis/releases).*

> 2.41.0
> ------
>
> What's Changed
> --------------
>
> * Pre-install the JavaScript RPC npm package before running tests by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-static-analysis#956](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/956)
> * UnnecessaryExplicitTypeArguments: retain witness for a return-only ty… by [`@​neil-mushell`](https://github.com/neil-mushell) in [openrewrite/rewrite-static-analysis#958](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/958)
> * Do not delete expressions that may have side effects by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-static-analysis#959](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/959)
> * OpenRewrite recipe best practices by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-static-analysis#960](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/960)
> * UseLambdaForFunctionalInterface: only convert when the anonymous class implements the SAM by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-static-analysis#962](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/962)
> * ReplaceStringBuilderWithString: wrap `char[]` appends in `String.valueOf` by [`@​martinfrancois`](https://github.com/martinfrancois) in [openrewrite/rewrite-static-analysis#977](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/977)
> * RemoveMethodsOnlyCallSuper: keep synchronized and deprecated overrides by [`@​martinfrancois`](https://github.com/martinfrancois) in [openrewrite/rewrite-static-analysis#971](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/971)
> * Make sure ModifierOrder doesn't alter Python's def quasi-modifier by [`@​greg-at-moderne`](https://github.com/greg-at-moderne) in [openrewrite/rewrite-static-analysis#981](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/981)
> * NullableOnMethodReturnType: only move annotations applicable to TYPE\_USE by [`@​martinfrancois`](https://github.com/martinfrancois) in [openrewrite/rewrite-static-analysis#968](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/968)
> * `FallThrough` to work only for Java files by [`@​greg-at-moderne`](https://github.com/greg-at-moderne) in [openrewrite/rewrite-static-analysis#982](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/982)
> * Retry a failed npx warm, and survive a machine without Node by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-static-analysis#984](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/984)
> * Make `DefaultComesLast` apply only to Java by [`@​greg-at-moderne`](https://github.com/greg-at-moderne) in [openrewrite/rewrite-static-analysis#983](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/983)
>
> New Contributors
> ----------------
>
> * [`@​martinfrancois`](https://github.com/martinfrancois) made their first contribution in [openrewrite/rewrite-static-analysis#977](https://redirect.github.com/openrewrite/rewrite-static-analysis/pull/977)
>
> **Full Changelog**: <openrewrite/rewrite-static-analysis@v2.40.0...v2.41.0>


Commits

* [`43b51de`](openrewrite/rewrite-static-analysis@43b51de) Make DefaultComesLast apply only to Java ([#983](https://redirect.github.com/openrewrite/rewrite-static-analysis/issues/983))
* [`5d08edd`](openrewrite/rewrite-static-analysis@5d08edd) Retry a failed npx warm, and survive a machine without Node ([#984](https://redirect.github.com/openrewrite/rewrite-static-analysis/issues/984))
* [`49ddf78`](openrewrite/rewrite-static-analysis@49ddf78) FallThrough to work only for Java files ([#982](https://redirect.github.com/openrewrite/rewrite-static-analysis/issues/982))
* [`9699a7e`](openrewrite/rewrite-static-analysis@9699a7e) NullableOnMethodReturnType: only move annotations applicable to TYPE\_USE ([#968](https://redirect.github.com/openrewrite/rewrite-static-analysis/issues/968))
* [`0c6f970`](openrewrite/rewrite-static-analysis@0c6f970) Make sure ModifierOrder doesn't alter Python's def quasi-modifier ([#981](https://redirect.github.com/openrewrite/rewrite-static-analysis/issues/981))
* [`6ef24c5`](openrewrite/rewrite-static-analysis@6ef24c5) RemoveMethodsOnlyCallSuper: keep synchronized and deprecated overrides ([#971](https://redirect.github.com/openrewrite/rewrite-static-analysis/issues/971))
* [`0d8f7d7`](openrewrite/rewrite-static-analysis@0d8f7d7) ReplaceStringBuilderWithString: wrap `char[]` appends in `String.valueOf` ([#977](https://redirect.github.com/openrewrite/rewrite-static-analysis/issues/977))
* [`9a15a92`](openrewrite/rewrite-static-analysis@9a15a92) OpenRewrite recipe best practices
* [`a394f54`](openrewrite/rewrite-static-analysis@a394f54) UnnecessaryExplicitTypeArguments: regression test for witness on varargs meth...
* [`0ecb6d8`](openrewrite/rewrite-static-analysis@0ecb6d8) Update Gradle wrapper to 9.7.0
* Additional commits viewable in [compare view](openrewrite/rewrite-static-analysis@v2.40.0...v2.41.0)
  
[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility\_score?dependency-name=org.openrewrite.recipe:rewrite-static-analysis&package-manager=maven&previous-version=2.40.0&new-version=2.41.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
  
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show  ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant