Skip to content

Commit

Permalink
added eventUploadPeriodMillis functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
djih committed Sep 2, 2015
1 parent c8aaa6b commit 603ea1d
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 38 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ You can configure Amplitude by passing an object as the third argument to the `i
// optional configuration options
saveEvents: true,
includeUtm: true,
includeReferrer: true
includeReferrer: true,
batchEvents: true,
eventUploadThreshold: 50
})

| option | description | default |
Expand All @@ -97,8 +99,9 @@ You can configure Amplitude by passing an object as the third argument to the `i
| uploadBatchSize | Maximum number of events to send to the server per request. | 100 |
| includeUtm | If `true`, finds utm parameters in the query string or the __utmz cookie, parses, and includes them as user propeties on all events uploaded. | `false` |
| includeReferrer | If `true`, includes `referrer` and `referring_domain` as user propeties on all events uploaded. | `false` |
| batchEvents | If `true`, events are uploaded only when the number of unsent events is greater than `eventUploadThreshold`. | `false` |
| eventUploadThreshold | Minimum number of events to send to the server per request if `batchEvents` is `true`. | 30 |
| batchEvents | If `true`, events are batched together and uploaded only when the number of unsent events is greater than or equal to `eventUploadThreshold` or after `eventUploadPeriodMillis` milliseconds have passed since the first unsent event was logged. | `false` |
| eventUploadThreshold | Minimum number of events to batch together per request if `batchEvents` is `true`. | 30 |
| eventUploadPeriodMillis | Amount of time in milliseconds that the SDK waits before uploading events if `batchEvents` is `true`. | 30*1000 |


# Advanced #
Expand Down
40 changes: 24 additions & 16 deletions amplitude.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ var DEFAULT_OPTIONS = {
unsentKey: 'amplitude_unsent',
uploadBatchSize: 100,
batchEvents: false,
eventUploadThreshold: 30
eventUploadThreshold: 30,
eventUploadPeriodMillis: 30 * 1000 // 30s
};
var LocalStorageKeys = {
LAST_EVENT_ID: 'amplitude_lastEventId',
Expand Down Expand Up @@ -199,6 +200,7 @@ Amplitude.prototype.init = function(apiKey, opt_userId, opt_config) {
this.options.uploadBatchSize = opt_config.uploadBatchSize || this.options.uploadBatchSize;
this.options.eventUploadThreshold = opt_config.eventUploadThreshold || this.options.eventUploadThreshold;
this.options.savedMaxCount = opt_config.savedMaxCount || this.options.savedMaxCount;
this.options.eventUploadPeriodMillis = opt_config.eventUploadPeriodMillis || this.options.eventUploadPeriodMillis;
}

Cookie.options({
Expand Down Expand Up @@ -228,9 +230,8 @@ Amplitude.prototype.init = function(apiKey, opt_userId, opt_config) {
}
}
}
if (this.shouldSendEvents()) {
this.sendEvents();
}

this._sendEventsIfReady();

if (this.options.includeUtm) {
this._initUtmData();
Expand Down Expand Up @@ -261,11 +262,21 @@ Amplitude.prototype.nextEventId = function() {
return this._eventId;
};

Amplitude.prototype.shouldSendEvents = function() {
var batchEvents = this.options.batchEvents;
var numEvents = this._unsentEvents.length;
var threshold = this.options.eventUploadThreshold;
return (!batchEvents && numEvents > 0) || (batchEvents && numEvents >= threshold);
Amplitude.prototype._sendEventsIfReady = function() {
if (this._unsentEvents.length === 0) {
return;
}

if (!this.options.batchEvents) {
this.sendEvents();
return;
}

if (this._unsentEvents.length >= this.options.eventUploadThreshold) {
this.sendEvents();
} else {
setTimeout(this.sendEvents.bind(this), this.options.eventUploadPeriodMillis);
}
};

var _loadCookieData = function(scope) {
Expand Down Expand Up @@ -490,9 +501,7 @@ Amplitude.prototype._logEvent = function(eventType, eventProperties, apiProperti
this.saveEvents();
}

if (this.shouldSendEvents()){
this.sendEvents();
}
this._sendEventsIfReady();

return eventId;
} catch (e) {
Expand Down Expand Up @@ -539,7 +548,7 @@ Amplitude.prototype.removeEvents = function (maxEventId) {
};

Amplitude.prototype.sendEvents = function() {
if (!this._sending && !this.options.optOut) {
if (!this._sending && !this.options.optOut && this._unsentEvents.length > 0) {
this._sending = true;
var url = ('https:' === window.location.protocol ? 'https' : 'http') + '://' +
this.options.apiEndpoint + '/';
Expand Down Expand Up @@ -572,9 +581,8 @@ Amplitude.prototype.sendEvents = function() {
}

// Send more events if any queued during previous send.
if (scope.shouldSendEvents()) {
scope.sendEvents();
}
scope._sendEventsIfReady();

} else if (status === 413) {
//log('request too large');
// Can't even get this one massive event through. Drop it.
Expand Down
4 changes: 2 additions & 2 deletions amplitude.min.js

Large diffs are not rendered by default.

40 changes: 24 additions & 16 deletions src/amplitude.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ var DEFAULT_OPTIONS = {
unsentKey: 'amplitude_unsent',
uploadBatchSize: 100,
batchEvents: false,
eventUploadThreshold: 30
eventUploadThreshold: 30,
eventUploadPeriodMillis: 30 * 1000 // 30s
};
var LocalStorageKeys = {
LAST_EVENT_ID: 'amplitude_lastEventId',
Expand Down Expand Up @@ -87,6 +88,7 @@ Amplitude.prototype.init = function(apiKey, opt_userId, opt_config) {
this.options.uploadBatchSize = opt_config.uploadBatchSize || this.options.uploadBatchSize;
this.options.eventUploadThreshold = opt_config.eventUploadThreshold || this.options.eventUploadThreshold;
this.options.savedMaxCount = opt_config.savedMaxCount || this.options.savedMaxCount;
this.options.eventUploadPeriodMillis = opt_config.eventUploadPeriodMillis || this.options.eventUploadPeriodMillis;
}

Cookie.options({
Expand Down Expand Up @@ -116,9 +118,8 @@ Amplitude.prototype.init = function(apiKey, opt_userId, opt_config) {
}
}
}
if (this.shouldSendEvents()) {
this.sendEvents();
}

this._sendEventsIfReady();

if (this.options.includeUtm) {
this._initUtmData();
Expand Down Expand Up @@ -149,11 +150,21 @@ Amplitude.prototype.nextEventId = function() {
return this._eventId;
};

Amplitude.prototype.shouldSendEvents = function() {
var batchEvents = this.options.batchEvents;
var numEvents = this._unsentEvents.length;
var threshold = this.options.eventUploadThreshold;
return (!batchEvents && numEvents > 0) || (batchEvents && numEvents >= threshold);
Amplitude.prototype._sendEventsIfReady = function() {
if (this._unsentEvents.length === 0) {
return;
}

if (!this.options.batchEvents) {
this.sendEvents();
return;
}

if (this._unsentEvents.length >= this.options.eventUploadThreshold) {
this.sendEvents();
} else {
setTimeout(this.sendEvents.bind(this), this.options.eventUploadPeriodMillis);
}
};

var _loadCookieData = function(scope) {
Expand Down Expand Up @@ -378,9 +389,7 @@ Amplitude.prototype._logEvent = function(eventType, eventProperties, apiProperti
this.saveEvents();
}

if (this.shouldSendEvents()){
this.sendEvents();
}
this._sendEventsIfReady();

return eventId;
} catch (e) {
Expand Down Expand Up @@ -427,7 +436,7 @@ Amplitude.prototype.removeEvents = function (maxEventId) {
};

Amplitude.prototype.sendEvents = function() {
if (!this._sending && !this.options.optOut) {
if (!this._sending && !this.options.optOut && this._unsentEvents.length > 0) {
this._sending = true;
var url = ('https:' === window.location.protocol ? 'https' : 'http') + '://' +
this.options.apiEndpoint + '/';
Expand Down Expand Up @@ -460,9 +469,8 @@ Amplitude.prototype.sendEvents = function() {
}

// Send more events if any queued during previous send.
if (scope.shouldSendEvents()) {
scope.sendEvents();
}
scope._sendEventsIfReady();

} else if (status === 413) {
//log('request too large');
// Can't even get this one massive event through. Drop it.
Expand Down
69 changes: 68 additions & 1 deletion test/amplitude.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,16 @@ describe('Amplitude', function() {

describe('logEvent', function() {

var clock;

beforeEach(function() {
clock = sinon.useFakeTimers();
amplitude.init(apiKey);
});

afterEach(function() {
reset();
clock.restore();
});

it('should send request', function() {
Expand Down Expand Up @@ -288,7 +292,12 @@ describe('Amplitude', function() {
});

it('should batch events sent', function() {
amplitude.init(apiKey, null, {batchEvents: true, eventUploadThreshold: 10});
var eventUploadPeriodMillis = 10*1000;
amplitude.init(apiKey, null, {
batchEvents: true,
eventUploadThreshold: 10,
eventUploadPeriodMillis: eventUploadPeriodMillis
});

for (var i = 0; i < 15; i++) {
amplitude.logEvent('Event', {index: i});
Expand All @@ -307,8 +316,66 @@ describe('Amplitude', function() {
var unsentEvents = amplitude._unsentEvents;
assert.lengthOf(unsentEvents, 5);
assert.deepEqual(unsentEvents[4].event_properties, {index: 14});

// remaining 5 events should be sent by the delayed sendEvent call
clock.tick(eventUploadPeriodMillis);
assert.lengthOf(server.requests, 2);
server.respondWith('success');
server.respond();
assert.lengthOf(amplitude._unsentEvents, 0);
var events = JSON.parse(querystring.parse(server.requests[1].requestBody).e);
assert.lengthOf(events, 5);
assert.deepEqual(events[4].event_properties, {index: 14});
});

it('should send events after a delay', function() {
var eventUploadPeriodMillis = 10*1000;
amplitude.init(apiKey, null, {
batchEvents: true,
eventUploadThreshold: 2,
eventUploadPeriodMillis: eventUploadPeriodMillis
});
amplitude.logEvent('Event');

// saveEvent should not have been called yet
assert.lengthOf(amplitude._unsentEvents, 1);
assert.lengthOf(server.requests, 0);

// saveEvent should be called after delay
clock.tick(eventUploadPeriodMillis);
assert.lengthOf(server.requests, 1);
server.respondWith('success');
server.respond();
var events = JSON.parse(querystring.parse(server.requests[0].requestBody).e);
assert.lengthOf(events, 1);
assert.deepEqual(events[0].event_type, 'Event');
});

it('should not send events after a delay if no events to send', function() {
var eventUploadPeriodMillis = 10*1000;
amplitude.init(apiKey, null, {
batchEvents: true,
eventUploadThreshold: 2,
eventUploadPeriodMillis: eventUploadPeriodMillis
});
amplitude.logEvent('Event1');
amplitude.logEvent('Event2');

// saveEvent triggered by 2 event batch threshold
assert.lengthOf(amplitude._unsentEvents, 2);
assert.lengthOf(server.requests, 1);
server.respondWith('success');
server.respond();
var events = JSON.parse(querystring.parse(server.requests[0].requestBody).e);
assert.lengthOf(events, 2);
assert.deepEqual(events[1].event_type, 'Event2');

// saveEvent should be called after delay, but no request made
assert.lengthOf(amplitude._unsentEvents, 0);
clock.tick(eventUploadPeriodMillis);
assert.lengthOf(server.requests, 1);
})

it('should back off on 413 status', function() {
amplitude.init(apiKey, null, {uploadBatchSize: 10});

Expand Down

0 comments on commit 603ea1d

Please sign in to comment.