Skip to content

Commit

Permalink
Added 'retry' event to networking engine
Browse files Browse the repository at this point in the history
This makes NetworkingEngine a FakeEventTarget, and gives it a 'retry'
event which is fired when there is a recoverable error that results in
a retry.

Closes #1529

Change-Id: I0c15ed20f4d6abf971d280263c6d62841daf440e
  • Loading branch information
theodab committed Aug 15, 2018
1 parent 73400f7 commit d32d951
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
26 changes: 26 additions & 0 deletions lib/net/networking_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,26 @@ goog.require('shaka.net.Backoff');
goog.require('shaka.util.AbortableOperation');
goog.require('shaka.util.ArrayUtils');
goog.require('shaka.util.Error');
goog.require('shaka.util.FakeEvent');
goog.require('shaka.util.FakeEventTarget');
goog.require('shaka.util.IDestroyable');
goog.require('shaka.util.ObjectUtils');
goog.require('shaka.util.OperationManager');


/**
* @event shaka.net.NetworkingEngine.RetryEvent
* @description Fired when the networking engine receives a recoverable error
* and retries.
* @property {string} type
* 'retry'
* @property {?shaka.util.Error} error
* The error that caused the retry. If it was a non-Shaka error, this is set
* to null.
* @exportDoc
*/


/**
* NetworkingEngine wraps all networking operations. This accepts plugins that
* handle the actual request. A plugin is registered using registerScheme.
Expand All @@ -41,9 +56,12 @@ goog.require('shaka.util.OperationManager');
* @struct
* @constructor
* @implements {shaka.util.IDestroyable}
* @extends {shaka.util.FakeEventTarget}
* @export
*/
shaka.net.NetworkingEngine = function(onSegmentDownloaded) {
shaka.util.FakeEventTarget.call(this);

/** @private {boolean} */
this.destroyed_ = false;

Expand All @@ -60,6 +78,8 @@ shaka.net.NetworkingEngine = function(onSegmentDownloaded) {
this.onSegmentDownloaded_ = onSegmentDownloaded || null;
};

goog.inherits(shaka.net.NetworkingEngine, shaka.util.FakeEventTarget);


/**
* Request types. Allows a filter to decide which requests to read/alter.
Expand Down Expand Up @@ -501,6 +521,12 @@ shaka.net.NetworkingEngine.prototype.send_ = function(
}

if (error && error.severity == shaka.util.Error.Severity.RECOVERABLE) {
// Don't pass in a non-shaka error, even if one is somehow thrown;
// instead, call the listener with a null error.
const errorOrNull = error instanceof shaka.util.Error ? error : null;
let event = new shaka.util.FakeEvent('retry', {'error': errorOrNull});
this.dispatchEvent(event);

// Move to the next URI.
index = (index + 1) % request.uris.length;
let shakaError = /** @type {shaka.util.Error} */(error);
Expand Down
62 changes: 62 additions & 0 deletions test/net/networking_engine_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,68 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ function() {
.then(done);
});

describe('\'retry\' event', function() {
/** @type {shaka.extern.Request} */
let request;
/** @type {jasmine.Spy} */
let retrySpy;

beforeEach(() => {
request = createRequest('reject://foo', {
maxAttempts: 3,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0,
});

retrySpy = jasmine.createSpy('retry listener');
networkingEngine.addEventListener('retry', Util.spyFunc(retrySpy));
});

it('is called on recoverable error', async () => {
let error1 = new shaka.util.Error(
shaka.util.Error.Severity.RECOVERABLE,
shaka.util.Error.Category.NETWORK,
shaka.util.Error.Code.HTTP_ERROR);
let error2 = new shaka.util.Error(
shaka.util.Error.Severity.RECOVERABLE,
shaka.util.Error.Category.NETWORK,
shaka.util.Error.Code.BAD_HTTP_STATUS);
let resolve = {
uri: '', data: new ArrayBuffer(0), headers: {},
};
rejectScheme.and.callFake(() => {
switch (rejectScheme.calls.count()) {
case 1: return shaka.util.AbortableOperation.failed(error1);
case 2: return shaka.util.AbortableOperation.failed(error2);
default: return shaka.util.AbortableOperation.completed(resolve);
}
});
await networkingEngine.request(requestType, request).promise;
expect(retrySpy.calls.count()).toEqual(2);
if (retrySpy.calls.count() == 2) {
const event1 = retrySpy.calls.argsFor(0)[0];
const event2 = retrySpy.calls.argsFor(1)[0];
expect(event1.error).toBe(error1);
expect(event2.error).toBe(error2);
}
});

it('is not called on critical errors', async () => {
error = new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.NETWORK,
shaka.util.Error.Code.HTTP_ERROR);
try {
await networkingEngine.request(requestType, request).promise;
fail('not reached');
} catch (unused) {
expect(retrySpy).not.toHaveBeenCalled();
}
});
});

describe('abort', function() {
/** @type {!shaka.util.Error} */
let abortError;
Expand Down

0 comments on commit d32d951

Please sign in to comment.