Skip to content

Commit

Permalink
Add possibility to queue tracking requests so they are sent in bulk (m…
Browse files Browse the repository at this point in the history
…atomo-org#13616)

* add possibility to queue requests

* add tests

* update changelog
  • Loading branch information
tsteur authored Nov 29, 2018
1 parent 1bea865 commit 970883b
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 112 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ The Product Changelog at **[matomo.org/changelog](https://matomo.org/changelog)*

## Matomo 3.8.0

### Breaking Changes
### New APIs

* It is now possible to queue a request on the JavaScript tracker using the method `queueRequest(requestUrl)`. This can be useful to group multiple tracking requests into one bulk request to reduce the number of tracking requests that are sent to your server making the tracking more efficient.
* The output type "save on disk" in the API method `ScheduledReport.generateReport` has been replaced by the download output type.

## Matomo 3.6.1
Expand Down
79 changes: 77 additions & 2 deletions js/piwik.js
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,8 @@ if (typeof JSON_PIWIK !== 'object' && typeof window.JSON === 'object' && window.
enableCrossDomainLinking, disableCrossDomainLinking, isCrossDomainLinkingEnabled, setCrossDomainLinkingTimeout, getCrossDomainLinkingUrlParameter,
addListener, enableLinkTracking, enableJSErrorTracking, setLinkTrackingTimer, getLinkTrackingTimer,
enableHeartBeatTimer, disableHeartBeatTimer, killFrame, redirectFile, setCountPreRendered,
trackGoal, trackLink, trackPageView, getNumTrackedPageViews, trackRequest, trackSiteSearch, trackEvent,
trackGoal, trackLink, trackPageView, getNumTrackedPageViews, trackRequest, queueRequest, trackSiteSearch, trackEvent,
requests, timeout, sendRequests, queueRequest,
setEcommerceView, addEcommerceItem, removeEcommerceItem, clearEcommerceCart, trackEcommerceOrder, trackEcommerceCartUpdate,
deleteCookie, deleteCookies, offsetTop, offsetLeft, offsetHeight, offsetWidth, nodeType, defaultView,
innerHTML, scrollLeft, scrollTop, currentStyle, getComputedStyle, querySelectorAll, splice,
Expand Down Expand Up @@ -1098,6 +1099,8 @@ if (typeof window.Piwik !== 'object') {

coreConsentCounter = 0,

trackerIdCounter = 0,

isPageUnloading = false;

/************************************************************
Expand Down Expand Up @@ -3229,7 +3232,10 @@ if (typeof window.Piwik !== 'object') {
configHasConsent = null, // initialized below

// holds all pending tracking requests that have not been tracked because we need consent
consentRequestsQueue = [];
consentRequestsQueue = [],

// a unique ID for this tracker during this request
uniqueTrackerId = trackerIdCounter++;

// Document title
try {
Expand Down Expand Up @@ -5584,6 +5590,58 @@ if (typeof window.Piwik !== 'object') {

return hookObj;
}

var requestQueue = {
requests: [],
timeout: null,
sendRequests: function () {
var requestsToTrack = this.requests;
this.requests = [];
if (requestsToTrack.length === 1) {
sendRequest(requestsToTrack[0]);
} else {
sendBulkRequest(requestsToTrack);
}
},
push: function (requestUrl) {
if (!requestUrl) {
return;
}
if (isPageUnloading) {
// we don't queue as we need to ensure the request will be sent when the page is unloading...
trackerInstance.trackRequest(requestUrl);
return;
}

this.requests.push(requestUrl);

if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
// we always extend by another 1.75 seconds after receiving a tracking request
this.timeout = setTimeout(function () {
requestQueue.timeout = null;
requestQueue.sendRequests();
}, 1750);

var trackerQueueId = 'RequestQueue' + uniqueTrackerId;
if (!Object.prototype.hasOwnProperty.call(plugins, trackerQueueId)) {
// we setup one unload handler per tracker...
// Piwik.addPlugin might not be defined at this point, we add the plugin directly also to make
// JSLint happy.
plugins[trackerQueueId] = {
unload: function () {
if (requestQueue.timeout) {
clearTimeout(requestQueue.timeout);
}
requestQueue.sendRequests();
}
};
}
}
};

/*</DEBUG>*/

/************************************************************
Expand Down Expand Up @@ -7196,6 +7254,23 @@ if (typeof window.Piwik !== 'object') {
});
};

/**
* Won't send the tracking request directly but wait for a short time to possibly send this tracking request
* along with other tracking requests in one go. This can reduce the number of requests send to your server.
* If the page unloads (user navigates to another page or closes the browser), then all remaining queued
* requests will be sent immediately so that no tracking request gets lost.
* Note: Any queued request may not be possible to be replayed in case a POST request is sent. Only queue
* requests that don't have to be replayed.
*
* @param request eg. "param=value&param2=value2"
*/
this.queueRequest = function (request) {
trackCallback(function () {
var fullRequest = getRequest(request);
requestQueue.push(fullRequest);
});
};

/**
* If the user has given consent previously and this consent was remembered, it will return the number
* in milliseconds since 1970/01/01 which is the date when the user has given consent. Please note that
Expand Down
Loading

0 comments on commit 970883b

Please sign in to comment.