Repository navigation
Hand off in-flight telemetry to a detached sender at exit - #1217
Conversation
Telemetry requests were awaited (up to 500ms) at exit and the schema event was only started at exit, so every short command inherited a network round trip. Events are now queued, sent in-process only once the command has outlived a short delay, and anything still unconfirmed at exit is handed to a detached copy of the CLI (--flush-telemetry) which delivers it after the parent is gone. Events carry a client uuid and timestamp so a resend can be de-duplicated. Fixes #1216
|
The changes in this PR will be included in the next version bump.
|
📦 Bundle size
dist/ only; native binaries are versioned separately and not counted here. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
varlock-website | 2760190 | Commit Preview URL Branch Preview URL |
Oct 13 2026, 09:12 PM |
varlock
@varlock/native-helper-darwin
@varlock/native-helper-linux-arm64
@varlock/native-helper-linux-x64
@varlock/native-helper-win32-x64
commit: |
There was a problem hiding this comment.
Caution
The detached sender can trigger an unbounded process-spawning loop when Bun preloads varlock/auto-load. Restore the existing CLI-child guard on the sender before merging.
Reviewed changes: Reviewed the telemetry queue, exit handoff, hidden sender entry point, and related documentation and tests.
- Deferred sending: Events gain a UUID and timestamp and remain queued until an unref'd 200ms timer starts in-process delivery.
- Detached handoff: A synchronous exit hook transfers unconfirmed events and pending schema usage to a detached CLI sender with ignored stdio and a 10-second request limit.
- Coverage and docs: Tests cover queue and handoff behavior, and the guide describes background delivery. All 75 focused tests passed after building the required workspace dependencies; the deployed Cloudflare relay's batch handling was not verified.
gpt-6.1-sol | 𝕏
…t recursion The sender now reads its events from a temp file (deleted once read) instead of an env var, so the payload has no size limit and is not visible in ps; the env var remains only as a fallback when the temp dir is unwritable. The sender is spawned with VARLOCK_TELEMETRY_DISABLED set so it can never record or spawn telemetry of its own. The telemetry guide now describes the handoff step by step.
The payload is a couple of small anonymized events and the environment is readable only by the same user, so the temp file only added a disk write at exit, a fallback path, and litter when a sender is killed before reading it.
There was a problem hiding this comment.
Important
The new temp-file handoff leaves files behind when the detached sender cannot be started. The existing preload-guard thread also remains partially addressed: the opt-out flag stops the unbounded telemetry chain, but sender startup can still re-run auto-load.
Reviewed changes: Reviewed the changes since 83b2688f to the sender payload transport and telemetry opt-out behavior.
- Moved payloads to files: Wrote pending events to a user-readable-only temp file, passed its path to the sender, and retained an environment fallback when writing fails.
- Disabled sender capture: Set
VARLOCK_TELEMETRY_DISABLED=1on detached senders while allowing delivery of handed-off events. - Expanded tests and docs: Covered file delivery, deletion, and environment fallback, and documented the handoff lifecycle. All 76 focused tests passed after building the required workspace dependencies.
gpt-6.1-sol | 𝕏
There was a problem hiding this comment.
ℹ️ No new issues found in this delta. Approval remains withheld because the existing preload-guard thread is still partially addressed.
Reviewed changes: Reviewed the changes since 0ece447a to the detached sender's payload transport.
- Moved handoff to the environment: Replaced temp-file delivery and its fallback with
__VARLOCK_TELEMETRY_EVENTS, removing disk writes and orphaned-file failure paths. - Updated sender coverage and docs: Removed file-path handling and cleanup tests, and documented environment-only delivery. The Varlock build and all 72 focused telemetry and command-tracking tests passed.
gpt-6.1-sol | 𝕏
…oad bails The CLI clears __VARLOCK_CLI_CHILD from its own env at startup, so the detached sender was spawned without it. Under bun with bunfig preload = ["varlock/auto-load"] the sender would have run auto-load, spawning a varlock load whose exit spawns another sender, forever. Restore the marker on the sender's env.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes: Reviewed the changes since 27601905 to the detached sender's preload guard.
- Restored the CLI-child guard: Set
CLI_CHILD_MARKERon the detached sender so Bun-preloadedvarlock/auto-loadskips resolution before sender dispatch. - Extended regression coverage: Asserted that the parent marker is absent and the sender marker is restored. All 74 focused telemetry and CLI-child marker tests passed after building the required workspace dependencies.
gpt-6.1-sol | 𝕏



Fixes #1216
varlock load(and sovarlock/auto-load) paid a variable network round trip on every run: the exit hook awaited in-flight telemetry requests for up to 500ms, and thecli_schema_loadedevent was only started at exit, so the wait was nearly always hit.Now:
fetch()client init (10-30ms of main-thread time) at all; long-running ones (varlock run,proxy) send and confirm delivery while they run, as before.varlock --flush-telemetry, events passed in its environment as__VARLOCK_TELEMETRY_EVENTS), spawned with stdio ignored and unref'd; the parent exits immediately. The handoff costs about 1ms (a spawn syscall); the child's startup happens after the parent is gone. The child posts all events in one request with a 10s timeout and runs withVARLOCK_TELEMETRY_DISABLEDset so it can never record or spawn telemetry of its own, and with__VARLOCK_CLI_CHILDset so a bunfig-preloadedvarlock/auto-loadinside it bails instead of spawning avarlock load(the CLI clears that marker from its own env at startup, so the handoff has to restore it). Nothing is written to disk.process.exit().uuidandtimestampso a resend of an event that was in flight at exit can be de-duplicated (PostHog honorsuuid; the relay still mints its ownevent_id, worth switching to the client uuid there).This is the same shape as Expo CLI (in-process for long commands, detached for short), Vercel CLI, Netlify CLI, Prisma, and
next dev. Astro and Nuxt just fire-and-forget because all their commands are long-lived; wrangler awaits with a 1s cap and eats the latency.Measured locally (
varlock load --format json-full --compact, release build, node):Verified the handoff and sender under node, bun, and the compiled standalone binary, and that
execFileSyncof the CLI (what auto-load does) returns as soon as the CLI exits.Docs: added a "How Events Are Sent" section to the telemetry guide describing the handoff step by step.