Skip to content

Commit 4f7f645

Browse files
authored
[Main][Task]31233527: Add a Config to Allow Users to Change RequestSizeLimitBytes (microsoft#2511)
* update * update * update * update
1 parent b5a24d5 commit 4f7f645

File tree

7 files changed

+194
-11
lines changed

7 files changed

+194
-11
lines changed

channels/1ds-post-js/src/DataModels.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ export interface IChannelConfiguration {
6060
*/
6161
disableAutoBatchFlushLimit?: boolean;
6262

63+
/**
64+
* [Optional] Sets the record and request size limit in bytes for serializer.
65+
* Default for record size (sync) is 65000, record size (async) is 2000000.
66+
* Default for request size (sync) is 65000, request size (async) is 3145728.
67+
* @since 3.3.7
68+
*/
69+
requestLimit?: IRequestSizeLimit;
70+
6371
/**
6472
* [Optional] The HTTP override that should be used to send requests, as an IXHROverride object.
6573
* By default during the unload of a page or if the event specifies that it wants to use sendBeacon() or sync fetch (with keep-alive),
@@ -326,6 +334,19 @@ export interface ICollectorWebResult {
326334
authLoginUrl?: string;
327335
}
328336

337+
export interface IRequestSizeLimit {
338+
/**
339+
* Request size limit in bytes for serializer.
340+
* The value should be two numbers array, with format [async request size limit, sync request size limit]
341+
*/
342+
requestLimit?: number[];
343+
/**
344+
* Record size limit in bytes for serializer.
345+
* The value should be two numbers array, with format [async record size limit, sync record size limit]
346+
*/
347+
recordLimit?: number[];
348+
}
349+
329350
/**
330351
* Post channel interface
331352
*/

channels/1ds-post-js/src/HttpManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export class HttpManager {
246246
}
247247

248248
_useBeacons = !isReactNative(); // Only use beacons if not running in React Native
249-
_serializer = new Serializer(_core, valueSanitizer, stringifyObjects, enableCompoundKey, getCommonSchemaMetaData, _excludeCsMetaData);
249+
_serializer = new Serializer(_core, valueSanitizer, stringifyObjects, enableCompoundKey, getCommonSchemaMetaData, _excludeCsMetaData, channelConfig);
250250

251251
if (!isNullOrUndefined(channelConfig.useSendBeacon)) {
252252
_useBeacons = !!channelConfig.useSendBeacon;

channels/1ds-post-js/src/Index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77

88
import { IPayloadData, IXHROverride, OnCompleteCallback, SendPOSTFunction } from "@microsoft/1ds-core-js";
99
import {
10-
BE_PROFILE, IChannelConfiguration, IPostChannel, NRT_PROFILE, PayloadListenerFunction, PayloadPreprocessorFunction, RT_PROFILE
10+
BE_PROFILE, IChannelConfiguration, IPostChannel, IRequestSizeLimit, NRT_PROFILE, PayloadListenerFunction, PayloadPreprocessorFunction,
11+
RT_PROFILE
1112
} from "./DataModels";
1213
import { PostChannel } from "./PostChannel";
1314

1415
export {
15-
PostChannel, IChannelConfiguration,
16+
PostChannel, IChannelConfiguration, IRequestSizeLimit,
1617
BE_PROFILE, NRT_PROFILE, RT_PROFILE, IXHROverride, IPostChannel,
1718
SendPOSTFunction, IPayloadData, PayloadPreprocessorFunction, PayloadListenerFunction, OnCompleteCallback
1819
};

channels/1ds-post-js/src/PostChannel.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616
import { IPromise, createPromise } from "@nevware21/ts-async";
1717
import { ITimerHandler, isPromiseLike, mathCeil, mathMax, mathMin, objDeepFreeze } from "@nevware21/ts-utils";
1818
import {
19-
BE_PROFILE, EventBatchNotificationReason, IChannelConfiguration, IPostChannel, IPostTransmissionTelemetryItem, NRT_PROFILE, RT_PROFILE
19+
BE_PROFILE, EventBatchNotificationReason, IChannelConfiguration, IPostChannel, IPostTransmissionTelemetryItem, IRequestSizeLimit,
20+
NRT_PROFILE, RT_PROFILE
2021
} from "./DataModels";
2122
import { EventBatch } from "./EventBatch";
2223
import { HttpManager } from "./HttpManager";
@@ -88,7 +89,8 @@ const defaultPostChannelConfig: IConfigDefaults<IChannelConfiguration> = objDeep
8889
maxEventRetryAttempts: { isVal: isNumber, v: MaxSendAttempts },
8990
maxUnloadEventRetryAttempts: { isVal: isNumber, v: MaxSyncUnloadSendAttempts},
9091
addNoResponse: undefValue,
91-
excludeCsMetaData: undefValue
92+
excludeCsMetaData: undefValue,
93+
requestLimit: {} as IRequestSizeLimit
9294
});
9395

9496
function isOverrideFn(httpXHROverride: any) {

channels/1ds-post-js/src/Serializer.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
SendRequestReason, arrIndexOf, doPerf, getCommonSchemaMetaData, getTenantId, isArray, isValueAssigned, objForEachKey, sanitizeProperty,
1212
strStartsWith
1313
} from "@microsoft/1ds-core-js";
14-
import { IPostTransmissionTelemetryItem } from "./DataModels";
14+
import { IChannelConfiguration, IPostTransmissionTelemetryItem, IRequestSizeLimit } from "./DataModels";
1515
import { EventBatch } from "./EventBatch";
1616
import { STR_EMPTY } from "./InternalConstants";
1717
import { mathMin, strSubstr } from "@nevware21/ts-utils";
@@ -149,8 +149,9 @@ export class Serializer {
149149
* @param enableCompoundKey - Should compound keys be enabled (defaults to false)
150150
* @param getEncodedTypeOverride - The callback to get the encoded type for a property defaults to ({@link getCommonSchemaMetaData }(...))
151151
* @param excludeCsMetaData - (!DANGER!) Should metadata be populated when encoding the event blob (defaults to false) - PII data will NOT be tagged as PII for backend processing
152+
* @param cfg channel cfg for setting request and record size limit
152153
*/
153-
constructor(perfManager?: IPerfManagerProvider, valueSanitizer?: IValueSanitizer, stringifyObjects?: boolean, enableCompoundKey?: boolean, getEncodedTypeOverride?: SerializerGetEncodedType, excludeCsMetaData?: boolean) {
154+
constructor(perfManager?: IPerfManagerProvider, valueSanitizer?: IValueSanitizer, stringifyObjects?: boolean, enableCompoundKey?: boolean, getEncodedTypeOverride?: SerializerGetEncodedType, excludeCsMetaData?: boolean, cfg?: IChannelConfiguration) {
154155
const strData = "data";
155156
const strBaseData = "baseData";
156157
const strExt = "ext";
@@ -161,6 +162,11 @@ export class Serializer {
161162
let _isReservedCache = {};
162163
let _excludeCsMetaData: boolean = !!excludeCsMetaData;
163164
let _getEncodedType: SerializerGetEncodedType = getEncodedTypeOverride || getCommonSchemaMetaData;
165+
let _sizeCfg = _getSizeLimtCfg(cfg);
166+
let _requestSizeLimitBytes = _validateSizeLimit(_sizeCfg.requestLimit, RequestSizeLimitBytes, 0);
167+
let _beaconRequestSizeLimitBytes = _validateSizeLimit(_sizeCfg.requestLimit, BeaconRequestSizeLimitBytes, 1);
168+
let _maxRecordSize = _validateSizeLimit(_sizeCfg.recordLimit, MaxRecordSize, 0);
169+
let _maxBeaconRecordSize = Math.min(_validateSizeLimit(_sizeCfg.recordLimit, MaxBeaconRecordSize, 1), _beaconRequestSizeLimitBytes);
164170

165171
dynamicProto(Serializer, this, (_self) => {
166172

@@ -193,8 +199,8 @@ export class Serializer {
193199
let sizeExceeded: IPostTransmissionTelemetryItem[] = [];
194200
let failedEvts: IPostTransmissionTelemetryItem[] = [];
195201
let isBeaconPayload = payload.isBeacon;
196-
let requestMaxSize = isBeaconPayload ? BeaconRequestSizeLimitBytes : RequestSizeLimitBytes;
197-
let recordMaxSize = isBeaconPayload ? MaxBeaconRecordSize : MaxRecordSize;
202+
let requestMaxSize = isBeaconPayload ? _beaconRequestSizeLimitBytes : _requestSizeLimitBytes;
203+
let recordMaxSize = isBeaconPayload ? _maxBeaconRecordSize : _maxRecordSize;
198204

199205
let lp = 0;
200206
let joinCount = 0;
@@ -480,6 +486,25 @@ export class Serializer {
480486

481487
}
482488

489+
function _validateSizeLimit(cfgVal: number[], defaultVal: number, idx: number): number {
490+
if (isArray(cfgVal)){
491+
let val = cfgVal[idx];
492+
if (val > 0 && val <= defaultVal) {
493+
return val;
494+
}
495+
}
496+
return defaultVal;
497+
}
498+
499+
function _getSizeLimtCfg(cfg?: IChannelConfiguration) {
500+
let defaultCfg = {} as IRequestSizeLimit;
501+
if (cfg && cfg.requestLimit) {
502+
return cfg.requestLimit;
503+
}
504+
return defaultCfg;
505+
}
506+
507+
483508
/**
484509
* @ignore
485510
* @param getEncodedType - The function to get the encoded type for the property

channels/1ds-post-js/test/Unit/src/PostChannelTest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ export class PostChannelTest extends AITestClass {
179179
maxUnloadEventRetryAttempts: 2,
180180
addNoResponse: undefValue,
181181
excludeCsMetaData: undefValue,
182+
requestLimit: {}
182183
};
183184
let actaulConfig = postChannel["_getDbgPlgTargets"]()[1];
184185
QUnit.assert.deepEqual(expectedConfig, actaulConfig, "default config should be set");

channels/1ds-post-js/test/Unit/src/SerializerTest.ts

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { AITestClass } from "@microsoft/ai-test-framework";
22
import { HttpManager } from '../../../src/HttpManager';
3-
import { AppInsightsCore, EventLatency, IEventProperty } from '@microsoft/1ds-core-js';
3+
import { AppInsightsCore, EventLatency, EventSendType, IEventProperty, SendRequestReason } from '@microsoft/1ds-core-js';
44
import { PostChannel, IXHROverride, IPayloadData } from '../../../src/Index';
5-
import { IPostTransmissionTelemetryItem, EventBatchNotificationReason } from '../../../src/DataModels';
5+
import { IPostTransmissionTelemetryItem, EventBatchNotificationReason, IChannelConfiguration } from '../../../src/DataModels';
66
import { Serializer } from '../../../src/Serializer';
7+
import { EventBatch } from "../../../src/EventBatch";
78

89

910
export class SerializerTest extends AITestClass {
@@ -36,6 +37,138 @@ export class SerializerTest extends AITestClass {
3637
}
3738
});
3839

40+
this.testCase({
41+
name: "Append payload with size limit channel config",
42+
test: () => {
43+
let cfg = {
44+
requestLimit: {
45+
requestLimit: [200, 200],
46+
recordLimit: [200,200]
47+
}
48+
} as IChannelConfiguration
49+
let serializer = new Serializer(null, null, null, false, null, null, cfg);
50+
let ikey = "1234-5678";
51+
let event: IPostTransmissionTelemetryItem = {
52+
name: "testEvent",
53+
iKey: ikey,
54+
latency: EventLatency.Normal, // Should not get serialized
55+
data: {
56+
"testObject.testProperty": 456
57+
},
58+
baseData: {}
59+
};
60+
let event1: IPostTransmissionTelemetryItem = {
61+
name: "testEvent1",
62+
iKey: ikey,
63+
latency: EventLatency.Normal, // Should not get serialized
64+
data: {
65+
"testObject.testProperty": 456
66+
},
67+
baseData: {}
68+
};
69+
70+
let payload = serializer.createPayload(0, false, false, false, SendRequestReason.NormalSchedule, EventSendType.Batched);
71+
let batch = EventBatch.create(ikey, [event, event1]);
72+
serializer.appendPayload(payload, batch, 100);
73+
let evts = payload.payloadBlob;
74+
let expectedPayload = "{\"name\":\"testEvent\",\"iKey\":\"o:1234\",\"data\":{\"baseData\":{},\"testObject.testProperty\":456}}" + "\n" +
75+
"{\"name\":\"testEvent1\",\"iKey\":\"o:1234\",\"data\":{\"baseData\":{},\"testObject.testProperty\":456}}"
76+
QUnit.assert.equal(evts, expectedPayload, "should contain both events");
77+
let overflow = payload.overflow;
78+
QUnit.assert.equal(overflow, null, "should not have overflow batch");
79+
let sizeExceed = payload.sizeExceed;
80+
QUnit.assert.equal(sizeExceed.length, 0, "should not have size exceed batch");
81+
}
82+
});
83+
84+
85+
this.testCase({
86+
name: "Append overflow payload with size limit channel config",
87+
test: () => {
88+
let cfg = {
89+
requestLimit: {
90+
recordLimit: [100,100],
91+
requestLimit: [100, 100]
92+
}
93+
} as IChannelConfiguration
94+
let serializer = new Serializer(null, null, null, false, null, null, cfg);
95+
let ikey = "1234-5678";
96+
let event: IPostTransmissionTelemetryItem = {
97+
name: "testEvent",
98+
iKey: ikey,
99+
latency: EventLatency.Normal, // Should not get serialized
100+
data: {
101+
"testObject.testProperty": 456
102+
},
103+
baseData: {}
104+
};
105+
let event1: IPostTransmissionTelemetryItem = {
106+
name: "testEvent1",
107+
iKey: ikey,
108+
latency: EventLatency.Normal, // Should not get serialized
109+
data: {
110+
"testObject.testProperty": 456
111+
},
112+
baseData: {}
113+
};
114+
115+
let payload = serializer.createPayload(0, false, false, false, SendRequestReason.NormalSchedule, EventSendType.Batched);
116+
let batch = EventBatch.create(ikey, [event, event1]);
117+
serializer.appendPayload(payload, batch, 100);
118+
let evts = payload.payloadBlob;
119+
QUnit.assert.equal(evts, "{\"name\":\"testEvent\",\"iKey\":\"o:1234\",\"data\":{\"baseData\":{},\"testObject.testProperty\":456}}", "should contain only one event");
120+
let overflow = payload.overflow;
121+
QUnit.assert.equal(overflow.count(), 1, "should have only one overflow batch");
122+
let overflowEvts = overflow.events();
123+
QUnit.assert.equal(overflowEvts.length, 1, "should have only one overflow event");
124+
QUnit.assert.equal(overflowEvts[0], event1, "overflow should have event1");
125+
}
126+
});
127+
128+
129+
this.testCase({
130+
name: "Append exceed size payload with size limit channel config",
131+
test: () => {
132+
let cfg = {
133+
requestLimit: {
134+
recordLimit: [100,100],
135+
requestLimit: [100, 100]
136+
}
137+
} as IChannelConfiguration
138+
let serializer = new Serializer(null, null, null, false, null, null, cfg);
139+
let ikey = "1234-5678";
140+
let event: IPostTransmissionTelemetryItem = {
141+
name: "testEvent",
142+
iKey: ikey,
143+
latency: EventLatency.Normal, // Should not get serialized
144+
data: {
145+
"testObject.testProperty": 456
146+
},
147+
baseData: {}
148+
};
149+
let largEvent: IPostTransmissionTelemetryItem = {
150+
name: "testEvent",
151+
iKey: ikey,
152+
latency: EventLatency.Normal, // Should not get serialized
153+
data: {
154+
"testObject.testProperty": new Array(100).join("a")
155+
},
156+
baseData: {}
157+
};
158+
let payload = serializer.createPayload(0, false, false, false, SendRequestReason.NormalSchedule, EventSendType.Batched);
159+
let largeBatch = EventBatch.create(ikey, [event, largEvent]);
160+
serializer.appendPayload(payload, largeBatch, 100);
161+
let evts = payload.payloadBlob;
162+
QUnit.assert.equal(evts, "{\"name\":\"testEvent\",\"iKey\":\"o:1234\",\"data\":{\"baseData\":{},\"testObject.testProperty\":456}}", "should have only one overflow batch");
163+
let sizeExceed = payload.sizeExceed;
164+
QUnit.assert.equal(sizeExceed.length, 1, "should have only one payload with size exceed");
165+
let sizeExceedBatch = sizeExceed[0];
166+
QUnit.assert.equal(sizeExceedBatch.count(), 1, "exceed Batch should have only one event");
167+
let sizeExceedEvts = sizeExceedBatch.events();
168+
QUnit.assert.equal(sizeExceedEvts[0], largEvent, "exceed batch should only contain large event")
169+
}
170+
});
171+
39172
this.testCase({
40173
name: 'getEventBlob without compoundKey support',
41174
test: () => {

0 commit comments

Comments
 (0)