@microsoft/1ds-post-js 3.1.10 → 3.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +123 -5
  2. package/bundle/{ms.post-3.1.10.gbl.js → ms.post-3.1.11.gbl.js} +163 -86
  3. package/bundle/ms.post-3.1.11.gbl.js.map +1 -0
  4. package/bundle/ms.post-3.1.11.gbl.min.js +7 -0
  5. package/bundle/ms.post-3.1.11.gbl.min.js.map +1 -0
  6. package/bundle/ms.post-3.1.11.integrity.json +46 -0
  7. package/bundle/{ms.post-3.1.10.js → ms.post-3.1.11.js} +163 -86
  8. package/bundle/ms.post-3.1.11.js.map +1 -0
  9. package/bundle/ms.post-3.1.11.min.js +7 -0
  10. package/bundle/ms.post-3.1.11.min.js.map +1 -0
  11. package/bundle/ms.post.gbl.js +162 -85
  12. package/bundle/ms.post.gbl.js.map +1 -1
  13. package/bundle/ms.post.gbl.min.js +2 -2
  14. package/bundle/ms.post.gbl.min.js.map +1 -1
  15. package/bundle/ms.post.integrity.json +17 -17
  16. package/bundle/ms.post.js +162 -85
  17. package/bundle/ms.post.js.map +1 -1
  18. package/bundle/ms.post.min.js +2 -2
  19. package/bundle/ms.post.min.js.map +1 -1
  20. package/dist/ms.post.js +101 -47
  21. package/dist/ms.post.js.map +1 -1
  22. package/dist/ms.post.min.js +2 -2
  23. package/dist/ms.post.min.js.map +1 -1
  24. package/dist-esm/src/BatchNotificationActions.js +1 -1
  25. package/dist-esm/src/ClockSkewManager.js +1 -1
  26. package/dist-esm/src/Constants.d.ts +1 -0
  27. package/dist-esm/src/Constants.js +2 -1
  28. package/dist-esm/src/Constants.js.map +1 -1
  29. package/dist-esm/src/DataModels.d.ts +49 -0
  30. package/dist-esm/src/DataModels.js +1 -1
  31. package/dist-esm/src/EventBatch.js +1 -1
  32. package/dist-esm/src/HttpManager.d.ts +1 -1
  33. package/dist-esm/src/HttpManager.js +63 -24
  34. package/dist-esm/src/HttpManager.js.map +1 -1
  35. package/dist-esm/src/Index.js +1 -1
  36. package/dist-esm/src/KillSwitch.js +1 -1
  37. package/dist-esm/src/PostChannel.js +51 -28
  38. package/dist-esm/src/PostChannel.js.map +1 -1
  39. package/dist-esm/src/RetryPolicy.js +1 -1
  40. package/dist-esm/src/Serializer.js +1 -1
  41. package/dist-esm/src/typings/XDomainRequest.js +1 -1
  42. package/package.json +2 -2
  43. package/src/Constants.ts +1 -0
  44. package/src/DataModels.ts +62 -1
  45. package/src/HttpManager.ts +67 -22
  46. package/src/PostChannel.ts +56 -28
  47. package/bundle/ms.post-3.1.10.gbl.js.map +0 -1
  48. package/bundle/ms.post-3.1.10.gbl.min.js +0 -7
  49. package/bundle/ms.post-3.1.10.gbl.min.js.map +0 -1
  50. package/bundle/ms.post-3.1.10.integrity.json +0 -46
  51. package/bundle/ms.post-3.1.10.js.map +0 -1
  52. package/bundle/ms.post-3.1.10.min.js +0 -7
  53. package/bundle/ms.post-3.1.10.min.js.map +0 -1
@@ -27,10 +27,14 @@ import { XDomainRequest as IXDomainRequest } from "./typings/XDomainRequest";
27
27
  import {
28
28
  defaultCacheControl, defaultContentType, DisabledPropertyName, Method, strApiKey, strAuthXToken, strCacheControl,
29
29
  strClientId, strClientVersion, strContentTypeHeader, strDropped, strKillDurationHeader, strKillDurationSecondsHeader,
30
- strKillTokensHeader, strMsaDeviceTicket, strMsfpc, strOther, strRequeue, strResponseFail, strSending, strTimeDeltaHeader,
30
+ strKillTokensHeader, strMsaDeviceTicket, strMsfpc, strNoResponseBody, strOther, strRequeue, strResponseFail, strSending, strTimeDeltaHeader,
31
31
  strTimeDeltaToApply, strUploadTime
32
32
  } from "./Constants";
33
33
 
34
+ const strSendAttempt = "sendAttempt";
35
+
36
+ const _noResponseQs = "&" + strNoResponseBody + "=true";
37
+
34
38
  // TypeScript removed this interface so we need to declare the global so we can check for it's existence.
35
39
  declare var XDomainRequest: {
36
40
  prototype: IXDomainRequest;
@@ -140,7 +144,7 @@ export class HttpManager {
140
144
  * @constructor
141
145
  * @param requestQueue - The queue that contains the requests to be sent.
142
146
  */
143
- constructor(maxEventsPerBatch: number, maxConnections: number, maxRetries: number, actions: BatchNotificationActions) {
147
+ constructor(maxEventsPerBatch: number, maxConnections: number, maxRequestRetriesBeforeBackoff: number, actions: BatchNotificationActions) {
144
148
  let _urlString: string = "?cors=true&" + strContentTypeHeader.toLowerCase() + "=" + defaultContentType;
145
149
  let _killSwitch: EVTKillSwitch = new EVTKillSwitch();
146
150
  let _paused = false;
@@ -159,6 +163,8 @@ export class HttpManager {
159
163
  let _cookieMgr: ICookieMgr;
160
164
  let _isUnloading = false;
161
165
  let _useHeaders = false;
166
+ let _xhrTimeout: number;
167
+ let _disableXhrSync: boolean;
162
168
 
163
169
  dynamicProto(HttpManager, this, (_self) => {
164
170
  let _sendCredentials = true;
@@ -189,10 +195,15 @@ export class HttpManager {
189
195
  enableCompoundKey = !!channelConfig.enableCompoundKey;
190
196
  }
191
197
 
198
+ _xhrTimeout = channelConfig.xhrTimeout;
199
+ _disableXhrSync = channelConfig.disableXhrSync;
200
+
192
201
  _useBeacons = !isReactNative(); // Only use beacons if not running in React Native
193
202
  _serializer = new Serializer(_core, valueSanitizer, stringifyObjects, enableCompoundKey);
194
203
 
195
204
  let syncHttpInterface = httpInterface;
205
+ let beaconHttpInterface: IXHROverride = channelConfig.alwaysUseXhrOverride ? httpInterface : null;
206
+ let fetchSyncHttpInterface: IXHROverride = channelConfig.alwaysUseXhrOverride ? httpInterface : null;
196
207
 
197
208
  if (!httpInterface) {
198
209
  _customHttpInterface = false;
@@ -232,8 +243,8 @@ export class HttpManager {
232
243
  _sendInterfaces = {
233
244
  [EventSendType.Batched]: httpInterface,
234
245
  [EventSendType.Synchronous]: syncHttpInterface || _getSenderInterface([TransportType.Xhr, TransportType.Fetch, TransportType.Beacon], true),
235
- [EventSendType.SendBeacon]: _getSenderInterface([TransportType.Beacon, TransportType.Fetch, TransportType.Xhr], true) || syncHttpInterface,
236
- [EventSendType.SyncFetch]: _getSenderInterface([TransportType.Fetch, TransportType.Beacon, TransportType.Xhr], true) || syncHttpInterface
246
+ [EventSendType.SendBeacon]: beaconHttpInterface || _getSenderInterface([TransportType.Beacon, TransportType.Fetch], true) || syncHttpInterface || _getSenderInterface([TransportType.Xhr], true),
247
+ [EventSendType.SyncFetch]: fetchSyncHttpInterface || _getSenderInterface([TransportType.Fetch, TransportType.Beacon], true) || syncHttpInterface || _getSenderInterface([TransportType.Xhr], true)
237
248
  };
238
249
  };
239
250
 
@@ -278,6 +289,9 @@ export class HttpManager {
278
289
  // It doesn't support custom headers, so no action is taken with current requestHeaders
279
290
  let xdr = new XDomainRequest();
280
291
  xdr.open(Method, payload.urlString);
292
+ if (payload.timeout) {
293
+ xdr.timeout = payload.timeout;
294
+ }
281
295
 
282
296
  // can't get the status code in xdr.
283
297
  xdr.onload = () => {
@@ -310,6 +324,7 @@ export class HttpManager {
310
324
  }
311
325
 
312
326
  function _fetchSendPost(payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) {
327
+ let theUrl = payload.urlString;
313
328
  let ignoreResponse = false;
314
329
  let responseHandled = false;
315
330
  let requestInit: RequestInit = {
@@ -324,6 +339,7 @@ export class HttpManager {
324
339
  // As a sync request (during unload), it is unlikely that we will get a chance to process the response so
325
340
  // just like beacon send assume that the events have been accepted and processed
326
341
  ignoreResponse = true;
342
+ theUrl += _noResponseQs;
327
343
  }
328
344
  }
329
345
 
@@ -337,7 +353,7 @@ export class HttpManager {
337
353
  requestInit.headers = payload.headers;
338
354
  }
339
355
 
340
- fetch(payload.urlString, requestInit).then((response) => {
356
+ fetch(theUrl, requestInit).then((response) => {
341
357
  let headerMap = {};
342
358
  let responseText = "";
343
359
  if (response.headers) {
@@ -370,9 +386,21 @@ export class HttpManager {
370
386
  responseHandled = true;
371
387
  _doOnComplete(oncomplete, 200, {});
372
388
  }
389
+
390
+ if (!responseHandled && payload.timeout > 0) {
391
+ // Simulate timeout
392
+ _postManager._setTimeoutOverride(() => {
393
+ if (!responseHandled) {
394
+ // Assume a 500 response (which will cause a retry)
395
+ responseHandled = true;
396
+ _doOnComplete(oncomplete, 500, {});
397
+ }
398
+ }, payload.timeout);
399
+ }
373
400
  }
374
401
 
375
402
  function _xhrSendPost(payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) {
403
+ let theUrl = payload.urlString;
376
404
 
377
405
  function _appendHeader(theHeaders, xhr, name) {
378
406
  if (!theHeaders[name] && xhr && xhr.getResponseHeader) {
@@ -405,25 +433,28 @@ export class HttpManager {
405
433
  function xhrComplete(xhr, responseTxt?) {
406
434
  _doOnComplete(oncomplete, xhr.status, _getAllResponseHeaders(xhr), responseTxt);
407
435
  }
436
+ if (sync && payload.disableXhrSync) {
437
+ sync = false;
438
+ }
408
439
 
409
- let xhRequest = openXhr(Method, payload.urlString, _sendCredentials, true, sync);
440
+ let xhrRequest = openXhr(Method, theUrl, _sendCredentials, true, sync, payload.timeout);
410
441
 
411
442
  // Set custom headers (e.g. gzip) here (after open())
412
443
  objForEachKey(payload.headers, (name, value) => {
413
- xhRequest.setRequestHeader(name, value);
444
+ xhrRequest.setRequestHeader(name, value);
414
445
  });
415
- xhRequest.onload = () => {
416
- let response = _getResponseText(xhRequest);
417
- xhrComplete(xhRequest, response);
446
+ xhrRequest.onload = () => {
447
+ let response = _getResponseText(xhrRequest);
448
+ xhrComplete(xhrRequest, response);
418
449
  _handleCollectorResponse(response);
419
450
  };
420
- xhRequest.onerror = () => {
421
- xhrComplete(xhRequest);
451
+ xhrRequest.onerror = () => {
452
+ xhrComplete(xhrRequest);
422
453
  };
423
- xhRequest.ontimeout = () => {
424
- xhrComplete(xhRequest);
454
+ xhrRequest.ontimeout = () => {
455
+ xhrComplete(xhrRequest);
425
456
  };
426
- xhRequest.send(payload.data);
457
+ xhrRequest.send(payload.data);
427
458
  }
428
459
 
429
460
  function _doOnComplete(oncomplete: OnCompleteCallback, status: number, headers: { [headerName: string]: string }, response?: string) {
@@ -440,9 +471,11 @@ export class HttpManager {
440
471
  let internalPayloadData = payload as IInternalPayloadData;
441
472
  let status = 200;
442
473
  let thePayload = internalPayloadData._thePayload;
474
+ let theUrl = payload.urlString + _noResponseQs;
475
+
443
476
  try {
444
477
  let nav = getNavigator();
445
- if (!nav.sendBeacon(payload.urlString, payload.data)) {
478
+ if (!nav.sendBeacon(theUrl, payload.data)) {
446
479
  if (thePayload) {
447
480
  // Failed to send entire payload so try and split data and try to send as much events as possible
448
481
  let droppedBatches: EventBatch[] = [];
@@ -450,7 +483,7 @@ export class HttpManager {
450
483
  if (droppedBatches && theBatch && theBatch.count() > 0) {
451
484
  let theEvents = theBatch.events();
452
485
  for (let lp = 0; lp < theEvents.length; lp++) {
453
- if (!nav.sendBeacon(payload.urlString, _serializer.getEventBlob(theEvents[lp]))) {
486
+ if (!nav.sendBeacon(theUrl, _serializer.getEventBlob(theEvents[lp]))) {
454
487
  // Can't send anymore, so split the batch and drop the rest
455
488
  droppedBatches.push(theBatch.split(lp));
456
489
  break;
@@ -809,7 +842,6 @@ export class HttpManager {
809
842
  useHeaders = useHeaders || requestDetails.useHdrs;
810
843
 
811
844
  let sendEventStart = getTime();
812
- let strSendAttempt = "sendAttempt";
813
845
 
814
846
  doPerf(_core, () => "HttpManager:_doPayloadSend", () => {
815
847
  // Increment the send attempt count and add timings after packaging (So it's not serialized in the 1st attempt)
@@ -844,9 +876,14 @@ export class HttpManager {
844
876
  urlString: requestDetails.url,
845
877
  headers: requestDetails.hdrs,
846
878
  _thePayload: thePayload,
847
- _sendReason: sendReason
879
+ _sendReason: sendReason,
880
+ timeout: _xhrTimeout
848
881
  };
849
882
 
883
+ if (!isUndefined(_disableXhrSync)) {
884
+ orgPayloadData.disableXhrSync = !!_disableXhrSync;
885
+ }
886
+
850
887
  // Only automatically add the following headers if already sending headers and we are not attempting to avoid an options call
851
888
  if (useHeaders) {
852
889
  if (!_hasHeader(orgPayloadData.headers, strCacheControl)) {
@@ -902,7 +939,9 @@ export class HttpManager {
902
939
  let hookData: IPayloadData = {
903
940
  data: orgPayloadData.data,
904
941
  urlString: orgPayloadData.urlString,
905
- headers: extend({}, orgPayloadData.headers)
942
+ headers: extend({}, orgPayloadData.headers),
943
+ timeout: orgPayloadData.timeout,
944
+ disableXhrSync: orgPayloadData.disableXhrSync
906
945
  };
907
946
 
908
947
  let senderCalled = false;
@@ -988,7 +1027,7 @@ export class HttpManager {
988
1027
 
989
1028
  // Disabling triple-equals rule to avoid httpOverrides from failing because they are returning a string value
990
1029
  // tslint:disable-next-line:triple-equals
991
- if (status == 200) {
1030
+ if (status == 200 || status == 204) {
992
1031
  // Response was successfully sent
993
1032
  reason = EventBatchNotificationReason.Complete;
994
1033
  return;
@@ -1008,7 +1047,8 @@ export class HttpManager {
1008
1047
  reason = EventBatchNotificationReason.RequeueEvents;
1009
1048
  let retryCount = thePayload.retryCnt;
1010
1049
  if (thePayload.sendType === EventSendType.Batched) {
1011
- if (retryCount < maxRetries) {
1050
+ // attempt to resend the entire batch
1051
+ if (retryCount < maxRequestRetriesBeforeBackoff) {
1012
1052
  isRetrying = true;
1013
1053
  _doAction(() => {
1014
1054
  // try to resend the same batches
@@ -1023,6 +1063,11 @@ export class HttpManager {
1023
1063
  }, _isUnloading, RetryPolicy.getMillisToBackoffForRetry(retryCount));
1024
1064
  } else {
1025
1065
  backOffTrans = true;
1066
+ if (_isUnloading) {
1067
+ // we are unloading so don't try and requeue the events otherwise let the events get requeued and resent during the backoff sending
1068
+ // This will also cause the events to be purged based on the priority (if necessary)
1069
+ reason = EventBatchNotificationReason.NonRetryableStatus;
1070
+ }
1026
1071
  }
1027
1072
  }
1028
1073
  }
@@ -8,7 +8,7 @@ import {
8
8
  EventLatency, NotificationManager, EventsDiscardedReason, IPlugin, ITelemetryItem,
9
9
  IAppInsightsCore, isValueAssigned, addPageUnloadEventListener, addPageHideEventListener, addPageShowEventListener, setProcessTelemetryTimings,
10
10
  isWindowObjectAvailable, IProcessTelemetryContext, SendRequestReason, arrForEach,
11
- LoggingSeverity, _ExtendedInternalMessageId, doPerf, objForEachKey, optimizeObject, isChromium, getWindow, EventSendType, addEventHandler, getDocument,
11
+ LoggingSeverity, _ExtendedInternalMessageId, doPerf, objForEachKey, optimizeObject, isChromium, getWindow, EventSendType, addEventHandler, getDocument, isBeaconsSupported, isReactNative, isFetchSupported, isNumber,
12
12
  } from "@microsoft/1ds-core-js";
13
13
  import {
14
14
  IChannelConfiguration, RT_PROFILE, NRT_PROFILE, IPostChannel,
@@ -25,14 +25,18 @@ const FlushCheckTimer = 0.250; // This needs to be in seconds, so this
25
25
  const MaxNumberEventPerBatch = 500;
26
26
  const EventsDroppedAtOneTime = 20;
27
27
  const MaxSendAttempts = 6;
28
+ const MaxSyncUnloadSendAttempts = 2; // Assuming 2 based on beforeunload and unload
28
29
  const MaxBackoffCount = 4;
29
30
  const globalContext = isWindowObjectAvailable ? window : this;
30
31
  const MaxConnections = 2;
31
- const MaxRetries = 1;
32
+ const MaxRequestRetriesBeforeBackoff = 1;
32
33
 
33
34
  const strEventsDiscarded = "eventsDiscarded";
34
35
  const strOverrideInstrumentationKey = "overrideInstrumentationKey";
35
36
 
37
+ const strMaxEventRetryAttempts = "maxEventRetryAttempts";
38
+ const strMaxUnloadEventRetryAttempts = "maxUnloadEventRetryAttempts";
39
+
36
40
  interface IPostChannelBatchQueue {
37
41
  /**
38
42
  * This is the actual queue of event batches
@@ -86,13 +90,16 @@ export default class PostChannel extends BaseTelemetryPlugin implements IChannel
86
90
  let _delayedBatchReason: SendRequestReason;
87
91
  let _optimizeObject: boolean = true;
88
92
  let _isPageUnloadTriggered = false;
93
+ let _disableXhrSync = false;
94
+ let _maxEventSendAttempts: number = MaxSendAttempts;
95
+ let _maxUnloadEventSendAttempts: number = MaxSyncUnloadSendAttempts;
89
96
 
90
97
  dynamicProto(PostChannel, this, (_self, _base) => {
91
98
  _initializeProfiles();
92
99
  _clearQueues();
93
100
  _setAutoLimits();
94
101
 
95
- _httpManager = new HttpManager(MaxNumberEventPerBatch, MaxConnections, MaxRetries, {
102
+ _httpManager = new HttpManager(MaxNumberEventPerBatch, MaxConnections, MaxRequestRetriesBeforeBackoff, {
96
103
  requeue: _requeueEvents,
97
104
  send: _sendingEvent,
98
105
  sent: _eventsSentEvent,
@@ -120,14 +127,7 @@ export default class PostChannel extends BaseTelemetryPlugin implements IChannel
120
127
  // Only try and use the optimizeObject() if this appears to be a chromium based browser and it has not been explicitly disabled
121
128
  _optimizeObject = !_config.disableOptimizeObj && isChromium();
122
129
 
123
- var existingGetWParamMethod = extendedCore.getWParam;
124
- extendedCore.getWParam = () => {
125
- var wparam = 0;
126
- if (_config.ignoreMc1Ms0CookieProcessing) {
127
- wparam = wparam | 2;
128
- }
129
- return wparam | existingGetWParamMethod();
130
- };
130
+ _hookWParam(extendedCore);
131
131
 
132
132
  if (_config.eventsLimitInMem > 0) {
133
133
  _queueSizeLimit = _config.eventsLimitInMem;
@@ -141,6 +141,15 @@ export default class PostChannel extends BaseTelemetryPlugin implements IChannel
141
141
  _autoFlushEventsLimit = _config.autoFlushEventsLimit;
142
142
  }
143
143
 
144
+ _disableXhrSync = _config.disableXhrSync;
145
+ if (isNumber(_config[strMaxEventRetryAttempts])) {
146
+ _maxEventSendAttempts = _config[strMaxEventRetryAttempts];
147
+ }
148
+
149
+ if (isNumber(_config[strMaxUnloadEventRetryAttempts])) {
150
+ _maxUnloadEventSendAttempts = _config[strMaxUnloadEventRetryAttempts];
151
+ }
152
+
144
153
  _setAutoLimits();
145
154
 
146
155
  if (_config.httpXHROverride && _config.httpXHROverride.sendPOST) {
@@ -157,27 +166,12 @@ export default class PostChannel extends BaseTelemetryPlugin implements IChannel
157
166
  _self._notificationManager = coreConfig.extensionConfig.NotificationManager;
158
167
  _httpManager.initialize(endpointUrl, _self.core as IExtendedAppInsightsCore, _self, _xhrOverride, _config);
159
168
 
160
- function _handleUnloadEvents(evt: any) {
161
- let theEvt = evt || getWindow().event; // IE 8 does not pass the event
162
- if (theEvt.type !== "beforeunload") {
163
- // Only set the unload trigger if not beforeunload event as beforeunload can be cancelled while the other events can't
164
- _isPageUnloadTriggered = true;
165
- _httpManager.setUnloading(_isPageUnloadTriggered);
166
- }
167
-
168
- _releaseAllQueues(EventSendType.SendBeacon, SendRequestReason.Unload);
169
- }
170
-
171
169
  let excludePageUnloadEvents = coreConfig.disablePageUnloadEvents || [];
172
170
 
173
171
  // When running in Web browsers try to send all telemetry if page is unloaded
174
172
  addPageUnloadEventListener(_handleUnloadEvents, excludePageUnloadEvents);
175
173
  addPageHideEventListener(_handleUnloadEvents, excludePageUnloadEvents);
176
- addPageShowEventListener((evt) => {
177
- // Handle the page becoming visible again
178
- _isPageUnloadTriggered = false;
179
- _httpManager.setUnloading(_isPageUnloadTriggered);
180
- }, coreConfig.disablePageShowEvents);
174
+ addPageShowEventListener(_handleShowEvents, coreConfig.disablePageShowEvents);
181
175
 
182
176
  _self.setInitialized(true);
183
177
  }, () => ({ coreConfig, core, extensions }));
@@ -222,6 +216,35 @@ export default class PostChannel extends BaseTelemetryPlugin implements IChannel
222
216
  _self.processNext(event, itemCtx);
223
217
  };
224
218
 
219
+ function _hookWParam(extendedCore: IExtendedAppInsightsCore) {
220
+ var existingGetWParamMethod = extendedCore.getWParam;
221
+ extendedCore.getWParam = () => {
222
+ var wparam = 0;
223
+ if (_config.ignoreMc1Ms0CookieProcessing) {
224
+ wparam = wparam | 2;
225
+ }
226
+ return wparam | existingGetWParamMethod();
227
+ };
228
+ }
229
+
230
+ // Moving event handlers out from the initialize closure so that any local variables can be garbage collected
231
+ function _handleUnloadEvents(evt: any) {
232
+ let theEvt = evt || getWindow().event; // IE 8 does not pass the event
233
+ if (theEvt.type !== "beforeunload") {
234
+ // Only set the unload trigger if not beforeunload event as beforeunload can be cancelled while the other events can't
235
+ _isPageUnloadTriggered = true;
236
+ _httpManager.setUnloading(_isPageUnloadTriggered);
237
+ }
238
+
239
+ _releaseAllQueues(EventSendType.SendBeacon, SendRequestReason.Unload);
240
+ }
241
+
242
+ function _handleShowEvents(evt: any) {
243
+ // Handle the page becoming visible again
244
+ _isPageUnloadTriggered = false;
245
+ _httpManager.setUnloading(_isPageUnloadTriggered);
246
+ }
247
+
225
248
  function _addEventToQueues(event: IPostTransmissionTelemetryItem, append: boolean) {
226
249
  // If send attempt field is undefined we should set it to 0.
227
250
  if (!event.sendAttempt) {
@@ -805,6 +828,11 @@ export default class PostChannel extends BaseTelemetryPlugin implements IChannel
805
828
  */
806
829
  function _requeueEvents(batches: EventBatch[], reason?: number) {
807
830
  let droppedEvents: IPostTransmissionTelemetryItem[] = [];
831
+ let maxSendAttempts = _maxEventSendAttempts;
832
+ if (_isPageUnloadTriggered) {
833
+ // If a page unlaod has been triggered reduce the number of times we try to "retry"
834
+ maxSendAttempts = _maxUnloadEventSendAttempts;
835
+ }
808
836
 
809
837
  arrForEach(batches, (theBatch) => {
810
838
  if (theBatch && theBatch.count() > 0) {
@@ -817,7 +845,7 @@ export default class PostChannel extends BaseTelemetryPlugin implements IChannel
817
845
  theEvent.sync = false;
818
846
  }
819
847
 
820
- if (theEvent.sendAttempt < MaxSendAttempts) {
848
+ if (theEvent.sendAttempt < maxSendAttempts) {
821
849
  // Reset the event timings
822
850
  setProcessTelemetryTimings(theEvent, _self.identifier);
823
851
  _addEventToQueues(theEvent, false);