Skip to content

v1.4.1

Latest

Choose a tag to compare

@jdwyah jdwyah released this 11 Sep 20:01
· 3 commits to main since this release
  • Fix (fork/telemetry): a forked child now reports under its OWN instanceHash (qfg-xcym). @instance_hash was minted once in Client#initialize and survived fork(2), so every forked child POSTed its telemetry under the parent's hash. The Quonfig Debugger groups SDK last-seen by that hash, so an 8-worker Puma cluster (or a parallel-gem batch) collapsed into a single instance row with the parent's and the children's windows interleaved on top of each other. A child now mints a fresh hash as part of the same post-fork rebuild that gives it fresh aggregators and a fresh reporter — before the reporter is constructed, so the hash the child POSTs under is its own. This is parity with Reforge, where a forked process simply builds a whole new client. The parent's hash is never touched, and a child's row count is unchanged (it already reported its own window; it just did so under the wrong identity). Present since 0.0.16.

  • Fix (telemetry): only a STRICTLY older payload counts as guardRejected (qfg-rr5b). The reject-older install guard treated an equal-generation payload as "older" and counted it, but two server behaviors re-deliver the envelope a client already holds in perfectly normal steady state: api-delivery's SSE sendInitialConfig re-sends the current envelope on every connect regardless of the Last-Event-Id the client sends, and a config poll against an empty per-leg ETag slot — a fresh transport, a reconnect, the fallback poller's engage fetch — answers with a full 200 at the same generation. A healthy client therefore reported guardRejected >= 1 from initialization alone and picked up another on every SSE reconnect, which is noise in a field whose entire purpose is to say "a leg tried to move us backwards". Semantic narrowing worth noting if you query this field: equal-generation re-deliveries are no longer counted, so guardRejected will read lower than on 1.4.0 for the same traffic — that is the fix, not a regression. Nothing else about the guard changed: an equal-generation envelope is still not installed, still returns :not_modified, and still advances the liveness stamp exactly where it did before, and the unversioned (generation <= 0) carve-out is untouched. No wire, ClickHouse, or dashboard-query change is required. This is the Ruby half of a change being applied across all six backend SDKs (sdk-python ships it in 1.4.1; Go, Java, .NET and Node follow in their next releases), so counts may differ across languages until then.

  • Docs (fork): a child forked from inside an on_update callback must exit (qfg-ec2q). on_update runs on the SDK's SSE reader thread, so a child created with non-block fork (no block) from inside that callback inherits that thread as its one surviving thread. If the child does its work and returns from the callback instead of exiting, the inherited reader resumes its read loop on the parent's socket and consumes frames the parent never sees. The README fork section now says to exit! (or exec) from such a child. Block-form fork { ... }, any child that exits, the documented patterns, and the parallel gem are all unaffected — no code change.

  • Include version in get request [#165]