mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 07:19:52 +00:00
feat(studio): add resolver-shadow attempt counter for soak-gate denominator (#1926)
* feat(studio): add resolver-shadow attempt counter for soak-gate denominator Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(studio): harden attempt-counter exception safety and tab-hide flush ordering PR review feedback (4 reviewers): recordAttempt() sat outside the try/catch in all three emit functions, so a throw inside it (e.g. setInterval/ addEventListener failing in a non-standard environment) would break the "never throws" contract. Also, the new visibilitychange listener races studioTelemetry.ts's own tab-hide handler — whichever fires first can beacon the queue before or after this module's rollup lands in it, silently dropping the attempt count for short sessions closed before the 5-minute timer fires. Fixes: move recordAttempt() inside each function's try block; export flushViaBeacon() from studioTelemetry.ts and call it explicitly after queuing the rollup, so delivery no longer depends on listener registration order; capture the visibilitychange handler by reference so __resetAttemptSchedulingForTests() actually removes it instead of leaking a duplicate on re-arm. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
74faa4b2a4
commit
fe821ff8bc
@@ -90,27 +90,34 @@ async function flushEvents(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronously drains the queue via sendBeacon — safe to call from any
|
||||
// tab-hide handler regardless of listener registration order. Exported so
|
||||
// other modules (e.g. sdkResolverShadow.ts) can force delivery of an event
|
||||
// they just queued without racing this module's own visibilitychange
|
||||
// listener below.
|
||||
export function flushViaBeacon(): void {
|
||||
if (flushTimer) {
|
||||
clearInterval(flushTimer);
|
||||
flushTimer = null;
|
||||
}
|
||||
if (queue.length === 0) return;
|
||||
const batch = queue.map((e) => ({
|
||||
event: e.event,
|
||||
properties: { ...e.properties, $ip: null },
|
||||
distinct_id: getDistinctId(),
|
||||
timestamp: e.timestamp,
|
||||
}));
|
||||
queue = [];
|
||||
const body = JSON.stringify({ api_key: POSTHOG_API_KEY, batch });
|
||||
try {
|
||||
navigator.sendBeacon(`${POSTHOG_HOST}/batch/`, body);
|
||||
} catch {
|
||||
// best-effort
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window.addEventListener("visibilitychange", () => {
|
||||
if (document.visibilityState === "hidden") {
|
||||
if (flushTimer) {
|
||||
clearInterval(flushTimer);
|
||||
flushTimer = null;
|
||||
}
|
||||
if (queue.length === 0) return;
|
||||
const batch = queue.map((e) => ({
|
||||
event: e.event,
|
||||
properties: { ...e.properties, $ip: null },
|
||||
distinct_id: getDistinctId(),
|
||||
timestamp: e.timestamp,
|
||||
}));
|
||||
queue = [];
|
||||
const body = JSON.stringify({ api_key: POSTHOG_API_KEY, batch });
|
||||
try {
|
||||
navigator.sendBeacon(`${POSTHOG_HOST}/batch/`, body);
|
||||
} catch {
|
||||
// best-effort
|
||||
}
|
||||
}
|
||||
if (document.visibilityState === "hidden") flushViaBeacon();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user