Do not track previously tracked failures

pull/21833/head
Luke Barnard 2018-06-15 14:48:20 +01:00
parent 4a8442901d
commit ac0416af96
2 changed files with 49 additions and 2 deletions

View File

@ -21,6 +21,10 @@ class DecryptionFailure {
} }
} }
function eventIdHash(eventId) {
return crypto.subtle.digest('SHA-256', eventId);
}
export default class DecryptionFailureTracker { export default class DecryptionFailureTracker {
// Array of items of type DecryptionFailure. Every `CHECK_INTERVAL_MS`, this list // Array of items of type DecryptionFailure. Every `CHECK_INTERVAL_MS`, this list
// is checked for failures that happened > `GRACE_PERIOD_MS` ago. Those that did // is checked for failures that happened > `GRACE_PERIOD_MS` ago. Those that did
@ -31,6 +35,11 @@ export default class DecryptionFailureTracker {
// one DecryptionFailure of this FIFO is removed and tracked. // one DecryptionFailure of this FIFO is removed and tracked.
failuresToTrack = []; failuresToTrack = [];
// Event IDs of failures that were tracked previously
eventTrackedPreviously = {
// [eventIdHash(eventId)]: true
};
// Spread the load on `Analytics` by sending at most 1 event per // Spread the load on `Analytics` by sending at most 1 event per
// `TRACK_INTERVAL_MS`. // `TRACK_INTERVAL_MS`.
static TRACK_INTERVAL_MS = 1000; static TRACK_INTERVAL_MS = 1000;
@ -112,10 +121,24 @@ export default class DecryptionFailureTracker {
// Only track one failure per event // Only track one failure per event
const dedupedFailuresMap = failuresGivenGrace.reduce( const dedupedFailuresMap = failuresGivenGrace.reduce(
(result, failure) => ({...result, [failure.failedEventId]: failure}), (result, failure) => {
if (!this.eventTrackedPreviously[eventIdHash(failure.failedEventId)]) {
return {...result, [failure.failedEventId]: failure};
} else {
return result;
}
},
{}, {},
); );
const dedupedFailures = Object.keys(dedupedFailuresMap).map((k) => dedupedFailuresMap[k]);
const trackedEventIds = Object.keys(dedupedFailuresMap);
this.eventTrackedPreviously = trackedEventIds.reduce(
(result, eventId) => ({...result, [eventIdHash(eventId)]: true}),
this.eventTrackedPreviously,
);
const dedupedFailures = trackedEventIds.map((k) => dedupedFailuresMap[k]);
this.failuresToTrack = [...this.failuresToTrack, ...dedupedFailures]; this.failuresToTrack = [...this.failuresToTrack, ...dedupedFailures];
} }

View File

@ -125,4 +125,28 @@ describe.only('DecryptionFailureTracker', function() {
done(); done();
}); });
it('should not track a failure for an event that was tracked previously', (done) => {
const decryptedEvent = createFailedDecryptionEvent();
const failures = [];
const tracker = new DecryptionFailureTracker((failure) => failures.push(failure));
// Indicate decryption
tracker.eventDecrypted(decryptedEvent);
// Pretend "now" is Infinity
tracker.checkFailures(Infinity);
tracker.trackFailure();
// Indicate a second decryption, after having tracked the failure
tracker.eventDecrypted(decryptedEvent);
tracker.trackFailure();
expect(failures.length).toBe(1, 'should only track a single failure per event');
done();
});
}); });