From d6653c9b0bc718c7e941f263b79ed50ae69dec88 Mon Sep 17 00:00:00 2001 From: Daniel Jackins Date: Mon, 1 Jul 2024 20:35:57 -0600 Subject: [PATCH 1/3] flush keepalive batches earlier --- .../__tests__/batched-dispatcher.test.ts | 25 +++++++++++++++++++ .../plugins/segmentio/batched-dispatcher.ts | 16 ++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/packages/browser/src/plugins/segmentio/__tests__/batched-dispatcher.test.ts b/packages/browser/src/plugins/segmentio/__tests__/batched-dispatcher.test.ts index d45ddd32a..869c9fc86 100644 --- a/packages/browser/src/plugins/segmentio/__tests__/batched-dispatcher.test.ts +++ b/packages/browser/src/plugins/segmentio/__tests__/batched-dispatcher.test.ts @@ -130,6 +130,31 @@ describe('Batching', () => { expect(fetch).toHaveBeenCalledTimes(1) }) + it('sends requests if the size of events exceeds keepalive limits', async () => { + const { dispatch } = batch(`https://api.segment.io`, { + size: 600, + keepalive: true, + }) + + // fatEvent is about ~1kb in size + for (let i = 0; i < 250; i++) { + await dispatch(`https://api.segment.io/v1/t`, { + event: 'small event', + }) + } + expect(fetch).not.toHaveBeenCalled() + + for (let i = 0; i < 65; i++) { + await dispatch(`https://api.segment.io/v1/t`, { + event: 'fat event', + properties: fatEvent, + }) + } + + // still called, even though our batch limit is 600 events + expect(fetch).toHaveBeenCalledTimes(1) + }) + it('sends requests when the timeout expires', async () => { const { dispatch } = batch(`https://api.segment.io`, { size: 100, diff --git a/packages/browser/src/plugins/segmentio/batched-dispatcher.ts b/packages/browser/src/plugins/segmentio/batched-dispatcher.ts index 1fb172d6a..91d7575c5 100644 --- a/packages/browser/src/plugins/segmentio/batched-dispatcher.ts +++ b/packages/browser/src/plugins/segmentio/batched-dispatcher.ts @@ -5,6 +5,7 @@ import { onPageChange } from '../../lib/on-page-change' export type BatchingDispatchConfig = { size?: number timeout?: number + keepalive?: boolean } const MAX_PAYLOAD_SIZE = 500 @@ -23,6 +24,15 @@ function approachingTrackingAPILimit(buffer: unknown): boolean { return kilobytes(buffer) >= MAX_PAYLOAD_SIZE - 50 } +/** + * Checks if payload is over the limit for keepalive + * requests. If keepalive is enabled we want to avoid + * going over this to prevent data loss. + */ +function passedKeepaliveLimit(buffer: unknown): boolean { + return kilobytes(buffer) >= 64 +} + function chunks(batch: object[]): Array { const result: object[][] = [] let index = 0 @@ -67,7 +77,7 @@ export default function batch( }) return fetch(`https://${apiHost}/b`, { - keepalive: pageUnloaded, + keepalive: config?.keepalive || pageUnloaded, headers: { 'Content-Type': 'text/plain', }, @@ -114,7 +124,9 @@ export default function batch( buffer.push(body) const bufferOverflow = - buffer.length >= limit || approachingTrackingAPILimit(buffer) + buffer.length >= limit || + approachingTrackingAPILimit(buffer) || + (config?.keepalive && passedKeepaliveLimit(buffer)) return bufferOverflow || pageUnloaded ? flush() : scheduleFlush() } From fd295d5e531aa5adc003ca759038bee220e3be7b Mon Sep 17 00:00:00 2001 From: Daniel Jackins Date: Tue, 2 Jul 2024 10:29:07 -0600 Subject: [PATCH 2/3] changeset --- .changeset/shaggy-dryers-press.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/shaggy-dryers-press.md diff --git a/.changeset/shaggy-dryers-press.md b/.changeset/shaggy-dryers-press.md new file mode 100644 index 000000000..efc9755a5 --- /dev/null +++ b/.changeset/shaggy-dryers-press.md @@ -0,0 +1,5 @@ +--- +'@segment/analytics-next': minor +--- + +Flush large keepalive requests From e6cba113184d4575a0d55fbe7fcd986939f0d30e Mon Sep 17 00:00:00 2001 From: Daniel Jackins Date: Tue, 2 Jul 2024 10:57:41 -0600 Subject: [PATCH 3/3] add small buffer --- packages/browser/src/plugins/segmentio/batched-dispatcher.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/browser/src/plugins/segmentio/batched-dispatcher.ts b/packages/browser/src/plugins/segmentio/batched-dispatcher.ts index 91d7575c5..bfc123c80 100644 --- a/packages/browser/src/plugins/segmentio/batched-dispatcher.ts +++ b/packages/browser/src/plugins/segmentio/batched-dispatcher.ts @@ -9,6 +9,7 @@ export type BatchingDispatchConfig = { } const MAX_PAYLOAD_SIZE = 500 +const MAX_KEEPALIVE_SIZE = 64 function kilobytes(buffer: unknown): number { const size = encodeURI(JSON.stringify(buffer)).split(/%..|./).length - 1 @@ -25,12 +26,12 @@ function approachingTrackingAPILimit(buffer: unknown): boolean { } /** - * Checks if payload is over the limit for keepalive + * Checks if payload is over or approaching the limit for keepalive * requests. If keepalive is enabled we want to avoid * going over this to prevent data loss. */ function passedKeepaliveLimit(buffer: unknown): boolean { - return kilobytes(buffer) >= 64 + return kilobytes(buffer) >= MAX_KEEPALIVE_SIZE - 10 } function chunks(batch: object[]): Array {