Skip to content

fix(bundler): restart the esbuild service after an unexpected child death instead of poisoning the process - #3718

Merged
kojiwakayama merged 8 commits into
mainfrom
fix/sentry-veryfront-server-v
Aug 14, 2026
Merged

fix(bundler): restart the esbuild service after an unexpected child death instead of poisoning the process#3718
kojiwakayama merged 8 commits into
mainfrom
fix/sentry-veryfront-server-v

Conversation

@kojiwakayama

@kojiwakayama kojiwakayama commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Fixes VERYFRONT-SERVER-V (160 events, staging, escalating).

Root cause

The immediate staging trigger (esbuild's module evaluating inside a project env scope and losing ESBUILD_BINARY_PATH) was fixed on main by #3698/#3697. This PR fixes the amplifier those left in place: when the managed esbuild service child dies unexpectedly (OOM-kill, SIGKILL, or the #3698-class spawn failure), the adapter latched a permanent process-wide ownership error. Every subsequent transform in the pod failed until restart, so one child death poisoned the whole process for its lifetime.

Fix

The bundler adapter now recovers with a fresh esbuild service after an unexpected managed child death, bounded by a restart budget (MAX_SERVICE_RESTARTS = 3) to preserve the original guard's protection against genuinely foreign service ownership. Operations in flight during a crash surface esbuild's raw transient error once; the next operation recovers.

The recovery path also preserves the module-wide ownership guardrails:

  • Raw esbuild services that replace a killed managed child remain rejected. Recovery and later shutdown calls fail closed without touching the foreign service.
  • Shutdown waits for operations that are already waiting on lost-service recovery, so stop() cannot complete and then leave that operation to spawn a new service afterward.
  • Build contexts captured before a managed service crash refresh themselves after recovery from the saved mapped options, so callers can keep using the existing BuildContext wrapper.
  • Managed child exit marks the service loss recoverable immediately, while close remains the completion signal, so operations launched in the exit-to-close window do not latch a permanent ownership error.
  • Stale plugin onDispose callbacks run before recreating a crashed context, preserving exactly one active plugin generation during context recovery.
  • Plugin generations are force-disposed when a crashed context is abandoned without rebuild, so abandoned esbuild services cannot strand plugin resources.
  • Forced cleanup reports only errors from the plugin generation being disposed while preserving the module-wide async disposal error for shutdown, so an unrelated stale disposal failure cannot poison later crashed-context cleanup.
  • Failed context refresh attempts dispose their attempted plugin generation and replace the abandoned mapped options with a fresh barrier, so a later successful retry can still await cleanup.
  • Restart-budget exhaustion stays latched even when stop() observes the lost service after the dead child has already closed and been cleared from module state.
  • stop() spends restart budget when it clears a managed crash, so crash plus stop loops cannot bypass the restart limit.

Testing (red-green TDD)

Regression coverage was added for managed child crash recovery, foreign raw-service replacement, repeated foreign shutdown, shutdown during pre-admission recovery, captured BuildContext reuse after recovery, the managed child exit-to-close window, stale plugin disposal before context recreation, abandoned crashed context disposal, stale disposal errors from unrelated plugin barriers, context refresh failure followed by a successful retry, and restart-budget exhaustion when losses are cleared by stop().

The new regressions fail on the pre-fix code: shutdown settles too early, stale context rebuild throws The service is no longer running, exit-to-close work latches the permanent module-wide ownership error, stale plugin disposal remains at 0 while a second setup runs, abandoned crashed contexts leave plugin disposal at 0, unrelated stale plugin disposal errors escape later crashed-context cleanup, failed refresh reuses an activated disposal barrier so later cleanup is not awaited, and crash plus stop loops let stop() resolve after the restart budget is exhausted.

Local verification at the pushed head (0efec7681e42b635a0fb897357941bd89f7c3d92):

  • deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts -> 8 passed, 38 steps.
  • deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src -> 12 passed, 46 steps.
  • deno fmt --check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts -> passed.
  • deno lint extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts -> passed.
  • deno check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts -> passed.
  • perl -CSD -ne 'print if /\\x{2014}|\\x{2013}/' extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts -> no matches.
  • git diff --check HEAD~1..HEAD -> passed.
  • Full pre-push hook at 0efec7681e42b635a0fb897357941bd89f7c3d92 -> passed: repo format, lint, typecheck, unit suite (3814 passed, 28499 steps, 0 failed, 1 ignored), cwd tests (10 passed, 193 steps), and cwd-exclusion tests (2 passed, 2 steps).

Reviewer notes

  • The restart budget never replenishes after successful recovery; 4 unexpected managed-child deaths over a long process lifetime re-latch the permanent error. A time-windowed budget would be more robust, but this PR keeps the guard simple and bounded.

…eath instead of poisoning the process

An OOM-kill or external signal that took down the managed esbuild service
child used to latch the permanent ownership error, failing every later
transform/bundle for the life of the process and streaming per-request
'Critical page module(s) failed to load' events to Sentry until the pod
restarted.

The close handler now records the death as a recoverable loss; the next
bundler operation resets esbuild's module state (its stop() clears the
cached dead service) and lets a fresh child spawn, bounded by a budget of
MAX_SERVICE_RESTARTS before the sticky ownership error still latches.
Genuinely foreign services - started while the adapter's spawn
interceptor was not installed - are still rejected permanently, and a
clean stop() clears any pending crash state.

Fixes VERYFRONT-SERVER-V
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@kojiwakayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2bb8b0df-46aa-4647-9534-2fbdc6d7471c

📥 Commits

Reviewing files that changed from the base of the PR and between 4eece1f and 0efec76.

📒 Files selected for processing (2)
  • extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts
  • extensions/ext-bundler-esbuild/src/esbuild-bundler.ts

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown

📦 Client bundle boundary

Entrypoint Modules Source size Server leaks
src/index.client.ts 454 3065 KiB ⚠️ 39 known

A server module in a client graph aborts hydration in the browser. New leaks fail CI; known leaks are tracked in scripts/lint/client-bundle-baseline.json to burn down.

A managed esbuild child can die while the shared esbuild module remains cached. If raw esbuild starts a replacement service before adapter recovery, module-wide stop would otherwise stop or adopt that foreign service. The adapter now guards the loss window, records any service spawn outside the adapter, and fails closed before recovery or shutdown can touch it.

Constraint: esbuild exposes only module-wide service state, not the current child owner

Rejected: Always call esbuild.stop() after a managed child death | can stop a raw service started after the managed child died

Confidence: high

Scope-risk: narrow

Directive: Do not reset a lost esbuild service through module-wide stop after observing a foreign service spawn

Tested: deno fmt --check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno lint extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src

Not-tested: full repository test suite
@kojiwakayama
kojiwakayama marked this pull request as ready for review August 14, 2026 18:34

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81fe3d7ec8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts
@kojiwakayama
kojiwakayama marked this pull request as draft August 14, 2026 18:49
A rejected crash recovery previously removed the temporary spawn guard while leaving the lost-service state active. That let a later shutdown enter esbuild's module-wide stop path even though a raw foreign service had replaced the killed managed child. The foreign replacement marker now survives guard removal so every later recovery or shutdown rejects before touching the module-wide service.

Constraint: esbuild exposes module-wide service state without an owner token

Rejected: Clear esbuildServiceLost after the first foreign rejection | later operations would lose the reason they must avoid module-wide stop

Confidence: high

Scope-risk: narrow

Directive: Foreign replacement state must outlive the temporary spawn guard until explicit test reset or process restart

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src

Tested: deno fmt --check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno lint extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: git diff --check

Not-tested: full pre-push hook pending at commit time
@kojiwakayama
kojiwakayama marked this pull request as ready for review August 14, 2026 19:03

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3320dcb447

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts Outdated
Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts
@kojiwakayama
kojiwakayama marked this pull request as draft August 14, 2026 19:09
A stop requested while an operation was waiting for lost-service recovery could finish before that operation was admitted, leaving the operation to spawn a fresh service after shutdown. Captured build contexts also retained the pre-crash esbuild context and failed after recovery. Non-reentrant operations now hold a stop barrier across pre-admission recovery, and build contexts refresh themselves when the managed service generation advances.

Constraint: esbuild exposes one module-wide service while the Bundler API exposes reusable contexts

Rejected: Fail captured contexts permanently after recovery | recreating from the saved mapped options preserves the public context contract

Confidence: high

Scope-risk: moderate

Directive: Do not let stop complete while an operation is between crash recovery and admission

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src

Tested: deno fmt --check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno lint extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: git diff --check

Not-tested: full pre-push hook pending at commit time
@kojiwakayama
kojiwakayama marked this pull request as ready for review August 14, 2026 19:25
@kojiwakayama
kojiwakayama marked this pull request as draft August 14, 2026 19:30

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 679916c8d3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts Outdated
Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts
Node emits child exit before close, so a managed child can already be non-live while the adapter has not yet marked the loss recoverable. The adapter now records recoverable managed loss at exit, keeps close as the completion signal, forces stale context plugin disposals before recreating a recovered context, and latches restart-budget exhaustion even after the dead child has been cleared from esbuildService.

Constraint: esbuild exposes only module-wide service state and does not dispose plugin callbacks when its service dies

Rejected: Treat exit-before-close as foreign ownership | the child is still the adapter-owned managed service

Confidence: high

Scope-risk: moderate

Directive: Managed child exit is the state transition for recovery; close is only the completion signal

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src

Tested: deno fmt --check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno lint extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: rg -n "—|–" extensions/ext-bundler-esbuild/src/esbuild-bundler.ts

Tested: git diff --check

Not-tested: full pre-push hook pending at commit time
@kojiwakayama
kojiwakayama marked this pull request as ready for review August 14, 2026 19:49

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e04a897ab9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts
Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts Outdated
Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts
@kojiwakayama
kojiwakayama marked this pull request as draft August 14, 2026 19:58
The adapter can observe a managed esbuild child death through paths that do not rebuild the stale context or that call stop before the next operation. Those paths now force plugin cleanup for the affected generation, treat an already-dead tracked child as a managed loss even before Node emits exit, and spend restart budget when stop resets a lost service.

Constraint: esbuild does not run plugin onDispose callbacks when its service dies underneath a context or request

Rejected: Force plugin cleanup on every build error | ordinary esbuild validation failures should keep the existing disposal barrier behavior

Rejected: Treat a tracked non-live child before exit as foreign ownership | the child is module-owned and still within the managed crash contract

Confidence: high

Scope-risk: moderate

Directive: If stop clears esbuildServiceLost, it must spend the same restart budget recovery would spend

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src

Tested: deno fmt --check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno lint extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: git diff --check

Tested: perl -CSD -ne 'print if /\x{2014}|\x{2013}/' extensions/ext-bundler-esbuild/src/esbuild-bundler.ts

Not-tested: full pre-push hook pending at commit time
@kojiwakayama
kojiwakayama marked this pull request as ready for review August 14, 2026 20:19

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c4974e3803

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts Outdated
Comment thread extensions/ext-bundler-esbuild/src/esbuild-bundler.ts Outdated
The in-flight context setup crash case can leave the esbuild request pending under Deno even though the live review blockers are covered by dispose-only context cleanup and stop-budget accounting. Removing that unstable extra case keeps the PR focused on deterministic recovery behavior.

Constraint: Current live review threads cover abandoned context disposal and stop-cleared loss accounting
Rejected: Keep the in-flight context setup test with a timeout | would test harness behavior more than adapter contract
Confidence: high
Scope-risk: narrow
Directive: Cover crash recovery through deterministic service ownership and disposal paths
Tested: PATH=/tmp/deno-2.7.7-aarch64-apple-darwin:$PATH deno fmt extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.ts
Tested: PATH=/tmp/deno-2.7.7-aarch64-apple-darwin:$PATH deno test --preload=src/testing/preload.ts --no-check --allow-all --filter 'service crash recovery' extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts
Tested: git diff --check
Not-tested: Full suite pending CI
@kojiwakayama
kojiwakayama marked this pull request as draft August 14, 2026 20:24
Context recovery can abandon one plugin disposal barrier and later create another. The barrier now reports only its own cleanup error while still publishing async failures for shutdown, and context refresh creates fresh mapped plugin options for each retry so a failed refresh cannot leave later generations activated.

Constraint: esbuild plugin onDispose callbacks are tied to a single service/context generation

Rejected: Clear the module-wide disposal error before forced cleanup | this would hide async cleanup failures that shutdown still needs to report

Rejected: Reuse one mapped plugin barrier across refresh retries | activation is one-shot and cannot safely represent later generations

Confidence: high

Scope-risk: narrow

Directive: Context refresh attempts must not reuse an activated plugin disposal barrier across service generations

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno test --preload=src/testing/preload.ts --no-check --allow-all extensions/ext-bundler-esbuild/src

Tested: deno fmt --check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno lint extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: deno check extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Tested: git diff --check

Tested: perl -CSD -ne 'print if /\x{2014}|\x{2013}/' extensions/ext-bundler-esbuild/src/esbuild-bundler.ts extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts

Not-tested: full pre-push hook pending at commit time
@kojiwakayama
kojiwakayama marked this pull request as ready for review August 14, 2026 20:50
@kojiwakayama

Copy link
Copy Markdown
Contributor Author

@codex review

@kojiwakayama
kojiwakayama added this pull request to the merge queue Aug 14, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0efec7681e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +827 to +829
trackedService && !trackedService.expectedClose && !isLiveService(trackedService) &&
remainingServiceRestarts <= 0
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Allow the final budgeted loss before latching exhaustion

When stop() runs after the third service's exit event but before its close event, esbuildService still references the dead child. The preceding loss handling decrements remainingServiceRestarts from 1 to 0, and this condition immediately records an ownership error, so the third loss is rejected even though MAX_SERVICE_RESTARTS explicitly permits it. The identical call succeeds if close happens first because that handler clears esbuildService, making shutdown behavior race-dependent; latch exhaustion only when a new loss is observed with no budget remaining. Add coverage for stopping between exit and close.

AGENTS.md reference: AGENTS.md:L11-L13

Useful? React with 👍 / 👎.

@kojiwakayama
kojiwakayama marked this pull request as draft August 14, 2026 20:54
Merged via the queue into main with commit a2356ca Aug 14, 2026
34 checks passed
@kojiwakayama
kojiwakayama deleted the fix/sentry-veryfront-server-v branch August 14, 2026 21:02
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.

1 participant