Skip to content

Remove nested turbo from package build scripts#26

Merged
Vadman97 merged 1 commit intomainfrom
fix/remove-nested-turbo-build
Apr 21, 2026
Merged

Remove nested turbo from package build scripts#26
Vadman97 merged 1 commit intomainfrom
fix/remove-nested-turbo-build

Conversation

@Vadman97
Copy link
Copy Markdown
Contributor

Summary

  • Replace \"build\": \"yarn turbo run prepublish\" in each package with the command the nested turbo was going to run (e.g. tsc -noEmit && vite build), matching the existing pattern in packages/utils.
  • The outer turbo invocation (e.g. turbo run build from a consumer repo) already walks the dep graph via ^build, so the nested layer was redundant — all it did was re-enter turbo from inside a workspace already being scheduled.

Why

On Linux, yarn build of a consumer project that depends on these packages (we hit this in launchdarkly/observability-sdk) would hang indefinitely with no subprocess activity. Every turbo process stuck in futex_wait_queue. No vite, no tsc ever spawned.

Root cause: each nested yarn turbo run prepublish re-runs turbo's root discovery from the package's own CWD, finds rrweb/package.json (with workspaces), and computes a repo-root hash different from the outer turbo's root hash. That means it tries to start its own turbo daemon — separate inotify instance, separate Unix socket under /tmp/turbod/<hash>/. When 10+ rrweb packages build in parallel, several nested turbos race to create the same daemon. On Linux, losing that race leaves you with a half-open socket connection to a daemon that's already been replaced, and you sit in futex_wait forever. macOS rarely hits this because kqueue/fsevents and BSD socket semantics resolve the race faster.

Observed symptom when stuck:

/tmp/turbod/
├── 2948c6004e604b3c/  # rrweb-snapshot CWD
├── 8be077b6d3282621/  # rrdom CWD
├── 973b7cc49da23c74/  # outer turbo root
└── e9931d89ef6fbc99/  # types CWD

Four daemons for one build = four root hashes = turbo thinks each package is its own root.

Additionally, most of these scripts were yarn turbo run prepublish without a -F filter, so each nested turbo tried to schedule prepublish across the entire rrweb workspace again — a graph the outer turbo had already walked.

After

Only one turbo daemon exists (the one the outer run starts). yarn build:sdk in observability-sdk goes from "stuck, need to cancel and retry 3× on Linux" to ~58s deterministic.

Semantics are preserved: each new build script is the verbatim body of the same package's prepublish script. prepublish is left in place since it's a yarn/npm publish lifecycle name.

Test plan

  • yarn build in observability-sdk on Linux — completes cleanly (18/18 tasks, no hang)
  • Verify CI still passes here
  • macOS sanity check (should be unaffected since it already completed; just faster now because of one fewer layer)

🤖 Generated with Claude Code

Each package's "build" script invoked `yarn turbo run prepublish`,
which re-enters turbo from inside a workspace already being built by
the outer turbo run. The nested invocation discovers a different
repo-root hash than the outer one, so it spawns its own turbo daemon
with its own inotify watches and Unix socket. When many rrweb
packages build in parallel, several nested turbos race to create the
same daemon and the losers deadlock in futex_wait on Linux (macOS is
more forgiving about socket/pidfile races and rarely hits this).

Inline each "build" with its own "prepublish" command (`tsc -noEmit
&& vite build`, etc.) — matching the pattern already used by
`packages/utils`. The outer turbo's graph already handles dep
ordering via ^build, so the nested layer was redundant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Vadman97 Vadman97 requested a review from a team April 21, 2026 20:14
@Vadman97 Vadman97 merged commit 5221048 into main Apr 21, 2026
9 of 16 checks passed
@Vadman97 Vadman97 deleted the fix/remove-nested-turbo-build branch April 21, 2026 21:47
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