Skip to content

feat: say how the browser died, not just that it is gone - #86

Open
nathanfallet wants to merge 1 commit into
mainfrom
feat/say-how-the-browser-died
Open

feat: say how the browser died, not just that it is gone#86
nathanfallet wants to merge 1 commit into
mainfrom
feat/say-how-the-browser-died

Conversation

@nathanfallet

@nathanfallet nathanfallet commented Aug 27, 2026

Copy link
Copy Markdown
Member

The problem

Since #83 a failed start reports alive=false: we know Chrome is gone, not how it went. The two possible deaths call for opposite investigations.

In production on 27/08, on the VMs still failing, the message is invariably:

Browser never opened its debug port on 127.0.0.1:53997 after 30500ms
(pid=8932, alive=false). Last connection error: ConnectException: Connection refused.
Browser stderr: <none>

Chrome starts, dies within 30s, and writes nothing. Did it crash, or did it stop on purpose? That decides where to look next, and today we cannot tell.

The change

Process.exitCodeOrNull() on all four targets:

  • jvmexitValue(), which throws IllegalThreadStateException while the process lives: that is exactly the "still running" case, reported as null.
  • mingwGetExitCodeProcess, the same call isAlive() already uses; null while it reports STILL_ACTIVE.
  • posixnull, deliberately: liveness there is kill(pid, 0), which does not carry a status, and nothing reaps the child to collect one.
  • js — unsupported, like the other process functions.

The status is reported verbatim, with no interpretation. There is a plausible reading of an exit 0 on Windows — Chrome hands its command line to an instance that already owns the same --user-data-dir and quits without opening a port — but that is a hypothesis, not something this PR asserts. Reading the status is the whole point: we do not know yet which statuses this failure produces, and putting a guess in every log line would defeat the instrumentation.

Scope

Message building moves to StartFailure.kt as two pure functions, processFate and browserStartFailureMessage, so the wording is covered by tests on any OS — the facts they report come from platform calls no CI can exercise.

Nothing changes on the happy path: both are only called in the failure branch.

Tests

Endpoint and pid always present; exit status reported verbatim for both 0 and non-zero; still-running said plainly; an unavailable status must not be reported as an exit code; stderr blank vs populated; last connection error.

All five targets compile, :core:jvmTest green, detekt 317 findings, same as main.

@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 35.71429% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../kotlin/dev/kdriver/core/browser/DefaultBrowser.kt 0.00% 6 Missing ⚠️
...in/kotlin/dev/kdriver/core/browser/StartFailure.kt 71.42% 0 Missing and 2 partials ⚠️
...ain/kotlin/dev/kdriver/core/browser/Process.jvm.kt 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

A failed start currently reports `alive=false`: we know Chrome is gone, not how it
went. The two possible deaths call for opposite investigations.

On the VMs failing in production on 27/08 the message is invariably:

    never opened its debug port ... (pid=8932, alive=false). Browser stderr: <none>

Chrome starts, dies within 30s, and writes nothing. Whether it crashed or chose to
stop is exactly what we cannot tell today — and it decides where to look next.

Adds `Process.exitCodeOrNull()` on all four targets:

- jvm: `exitValue()`, which throws while the process lives — hence the null.
- mingw: `GetExitCodeProcess`, the same call `isAlive()` already uses.
- posix: null. Liveness there is `kill(pid, 0)`, which does not carry a status,
  and nothing reaps the child to collect one.
- js: unsupported, like the other process functions.

The status is reported verbatim, with no interpretation. Reading it is the whole
point: we do not know yet which statuses this failure produces, and baking a guess
into every log line would make the instrumentation useless.

Message building moves to `StartFailure.kt` as two pure functions (`processFate`,
`browserStartFailureMessage`) covered by tests on any OS — the facts they report
come from platform calls no CI can exercise.

Nothing changes on the happy path: these are only called in the failure branch.
@nathanfallet
nathanfallet force-pushed the feat/say-how-the-browser-died branch from a7eac02 to fb9b4be Compare August 27, 2026 11:19
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