ui: Reconcile ember-data store when records are deleted via blocking (#5745)
* ui: Reconciliate ember-data store when records are deleted via blocking Currently we are barely using the ember-data store/cache, but it will still cache records in the store even though technically we aren't using it. This adds a SyncTime to every record that uses blocking queries so we can delete older records from the ember-data cache to prevent them building up * ui: Add basic timestamp method we can access from tests, fixup tests Adds a timestamp method that we can access from within tests so we can test that the SyncTime is being set. There is probably a better way to do this, but this is also probably the simplest approach - we are also likely to revisit this at a later date
This commit is contained in:
parent
fdd8aa5f2e
commit
f9710c2c92
|
@ -10,4 +10,5 @@ export default Model.extend({
|
||||||
Coord: attr(),
|
Coord: attr(),
|
||||||
Segment: attr('string'),
|
Segment: attr('string'),
|
||||||
Datacenter: attr('string'),
|
Datacenter: attr('string'),
|
||||||
|
SyncTime: attr('number'),
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,6 +21,7 @@ export default Model.extend({
|
||||||
Datacenter: attr('string'),
|
Datacenter: attr('string'),
|
||||||
Segment: attr(),
|
Segment: attr(),
|
||||||
Coord: attr(),
|
Coord: attr(),
|
||||||
|
SyncTime: attr('number'),
|
||||||
meta: attr(),
|
meta: attr(),
|
||||||
hasStatus: function(status) {
|
hasStatus: function(status) {
|
||||||
return hasStatus(get(this, 'Checks'), status);
|
return hasStatus(get(this, 'Checks'), status);
|
||||||
|
|
|
@ -10,4 +10,5 @@ export default Model.extend({
|
||||||
ServiceID: attr('string'),
|
ServiceID: attr('string'),
|
||||||
Node: attr('string'),
|
Node: attr('string'),
|
||||||
ServiceProxy: attr(),
|
ServiceProxy: attr(),
|
||||||
|
SyncTime: attr('number'),
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,6 +31,7 @@ export default Model.extend({
|
||||||
Node: attr(),
|
Node: attr(),
|
||||||
Service: attr(),
|
Service: attr(),
|
||||||
Checks: attr(),
|
Checks: attr(),
|
||||||
|
SyncTime: attr('number'),
|
||||||
meta: attr(),
|
meta: attr(),
|
||||||
passing: computed('ChecksPassing', 'Checks', function() {
|
passing: computed('ChecksPassing', 'Checks', function() {
|
||||||
let num = 0;
|
let num = 0;
|
||||||
|
|
|
@ -20,4 +20,5 @@ export default Model.extend({
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Datacenter: attr('string'),
|
Datacenter: attr('string'),
|
||||||
|
SyncTime: attr('number'),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Serializer from 'ember-data/serializers/rest';
|
import Serializer from 'ember-data/serializers/rest';
|
||||||
|
|
||||||
import { get } from '@ember/object';
|
import { set } from '@ember/object';
|
||||||
import {
|
import {
|
||||||
HEADERS_SYMBOL as HTTP_HEADERS_SYMBOL,
|
HEADERS_SYMBOL as HTTP_HEADERS_SYMBOL,
|
||||||
HEADERS_INDEX as HTTP_HEADERS_INDEX,
|
HEADERS_INDEX as HTTP_HEADERS_INDEX,
|
||||||
|
@ -44,14 +44,17 @@ export default Serializer.extend({
|
||||||
requestType
|
requestType
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
timestamp: function() {
|
||||||
|
return new Date().getTime();
|
||||||
|
},
|
||||||
normalizeMeta: function(store, primaryModelClass, headers, payload, id, requestType) {
|
normalizeMeta: function(store, primaryModelClass, headers, payload, id, requestType) {
|
||||||
const meta = {
|
const meta = {
|
||||||
cursor: headers[HTTP_HEADERS_INDEX],
|
cursor: headers[HTTP_HEADERS_INDEX],
|
||||||
date: headers['date'],
|
|
||||||
};
|
};
|
||||||
if (requestType === 'query') {
|
if (requestType === 'query') {
|
||||||
meta.ids = payload.map(item => {
|
meta.date = this.timestamp();
|
||||||
return get(item, this.primaryKey);
|
payload.forEach(function(item) {
|
||||||
|
set(item, 'SyncTime', meta.date);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return meta;
|
return meta;
|
||||||
|
|
|
@ -6,8 +6,27 @@ import LazyProxyService from 'consul-ui/services/lazy-proxy';
|
||||||
import { cache as createCache, BlockingEventSource } from 'consul-ui/utils/dom/event-source';
|
import { cache as createCache, BlockingEventSource } from 'consul-ui/utils/dom/event-source';
|
||||||
|
|
||||||
const createProxy = function(repo, find, settings, cache, serialize = JSON.stringify) {
|
const createProxy = function(repo, find, settings, cache, serialize = JSON.stringify) {
|
||||||
// proxied find*..(id, dc)
|
|
||||||
const client = get(this, 'client');
|
const client = get(this, 'client');
|
||||||
|
const store = get(this, 'store');
|
||||||
|
// custom createEvent, here used to reconcile the ember-data store for each tick
|
||||||
|
const createEvent = function(result, configuration) {
|
||||||
|
const event = {
|
||||||
|
type: 'message',
|
||||||
|
data: result,
|
||||||
|
};
|
||||||
|
const meta = get(event.data || {}, 'meta');
|
||||||
|
if (typeof meta.date !== 'undefined') {
|
||||||
|
// unload anything older than our current sync date/time
|
||||||
|
store.peekAll(repo.getModelName()).forEach(function(item) {
|
||||||
|
const date = get(item, 'SyncTime');
|
||||||
|
if (typeof date !== 'undefined' && date != meta.date) {
|
||||||
|
store.unloadRecord(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
};
|
||||||
|
// proxied find*..(id, dc)
|
||||||
return function() {
|
return function() {
|
||||||
const key = `${repo.getModelName()}.${find}.${serialize([...arguments])}`;
|
const key = `${repo.getModelName()}.${find}.${serialize([...arguments])}`;
|
||||||
const _args = arguments;
|
const _args = arguments;
|
||||||
|
@ -48,6 +67,7 @@ const createProxy = function(repo, find, settings, cache, serialize = JSON.strin
|
||||||
settings: {
|
settings: {
|
||||||
enabled: settings.blocking,
|
enabled: settings.blocking,
|
||||||
},
|
},
|
||||||
|
createEvent: createEvent,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
import { moduleFor, test } from 'ember-qunit';
|
import { moduleFor, test } from 'ember-qunit';
|
||||||
import repo from 'consul-ui/tests/helpers/repo';
|
import repo from 'consul-ui/tests/helpers/repo';
|
||||||
|
import { get } from '@ember/object';
|
||||||
const NAME = 'coordinate';
|
const NAME = 'coordinate';
|
||||||
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
||||||
// Specify the other units that are required for this test.
|
// Specify the other units that are required for this test.
|
||||||
integration: true
|
integration: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dc = 'dc-1';
|
const dc = 'dc-1';
|
||||||
|
const now = new Date().getTime();
|
||||||
test('findAllByDatacenter returns the correct data for list endpoint', function(assert) {
|
test('findAllByDatacenter returns the correct data for list endpoint', function(assert) {
|
||||||
|
get(this.subject(), 'store').serializerFor(NAME).timestamp = function() {
|
||||||
|
return now;
|
||||||
|
};
|
||||||
return repo(
|
return repo(
|
||||||
'Coordinate',
|
'Coordinate',
|
||||||
'findAllByDatacenter',
|
'findAllByDatacenter',
|
||||||
|
@ -26,6 +31,7 @@ test('findAllByDatacenter returns the correct data for list endpoint', function(
|
||||||
expected(function(payload) {
|
expected(function(payload) {
|
||||||
return payload.map(item =>
|
return payload.map(item =>
|
||||||
Object.assign({}, item, {
|
Object.assign({}, item, {
|
||||||
|
SyncTime: now,
|
||||||
Datacenter: dc,
|
Datacenter: dc,
|
||||||
uid: `["${dc}","${item.Node}"]`,
|
uid: `["${dc}","${item.Node}"]`,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { moduleFor, test } from 'ember-qunit';
|
import { moduleFor, test } from 'ember-qunit';
|
||||||
import repo from 'consul-ui/tests/helpers/repo';
|
import repo from 'consul-ui/tests/helpers/repo';
|
||||||
|
import { get } from '@ember/object';
|
||||||
const NAME = 'node';
|
const NAME = 'node';
|
||||||
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
||||||
// Specify the other units that are required for this test.
|
// Specify the other units that are required for this test.
|
||||||
|
@ -8,7 +9,11 @@ moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
||||||
|
|
||||||
const dc = 'dc-1';
|
const dc = 'dc-1';
|
||||||
const id = 'token-name';
|
const id = 'token-name';
|
||||||
|
const now = new Date().getTime();
|
||||||
test('findByDatacenter returns the correct data for list endpoint', function(assert) {
|
test('findByDatacenter returns the correct data for list endpoint', function(assert) {
|
||||||
|
get(this.subject(), 'store').serializerFor(NAME).timestamp = function() {
|
||||||
|
return now;
|
||||||
|
};
|
||||||
return repo(
|
return repo(
|
||||||
'Node',
|
'Node',
|
||||||
'findAllByDatacenter',
|
'findAllByDatacenter',
|
||||||
|
@ -27,6 +32,7 @@ test('findByDatacenter returns the correct data for list endpoint', function(ass
|
||||||
expected(function(payload) {
|
expected(function(payload) {
|
||||||
return payload.map(item =>
|
return payload.map(item =>
|
||||||
Object.assign({}, item, {
|
Object.assign({}, item, {
|
||||||
|
SyncTime: now,
|
||||||
Datacenter: dc,
|
Datacenter: dc,
|
||||||
uid: `["${dc}","${item.ID}"]`,
|
uid: `["${dc}","${item.ID}"]`,
|
||||||
})
|
})
|
||||||
|
@ -56,7 +62,6 @@ test('findBySlug returns the correct data for item endpoint', function(assert) {
|
||||||
Datacenter: dc,
|
Datacenter: dc,
|
||||||
uid: `["${dc}","${item.ID}"]`,
|
uid: `["${dc}","${item.ID}"]`,
|
||||||
meta: {
|
meta: {
|
||||||
date: undefined,
|
|
||||||
cursor: undefined,
|
cursor: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { moduleFor, test } from 'ember-qunit';
|
import { moduleFor, test } from 'ember-qunit';
|
||||||
import { skip } from 'qunit';
|
import { skip } from 'qunit';
|
||||||
import repo from 'consul-ui/tests/helpers/repo';
|
import repo from 'consul-ui/tests/helpers/repo';
|
||||||
|
import { get } from '@ember/object';
|
||||||
const NAME = 'service';
|
const NAME = 'service';
|
||||||
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
||||||
// Specify the other units that are required for this test.
|
// Specify the other units that are required for this test.
|
||||||
|
@ -8,7 +9,11 @@ moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
||||||
});
|
});
|
||||||
const dc = 'dc-1';
|
const dc = 'dc-1';
|
||||||
const id = 'token-name';
|
const id = 'token-name';
|
||||||
|
const now = new Date().getTime();
|
||||||
test('findByDatacenter returns the correct data for list endpoint', function(assert) {
|
test('findByDatacenter returns the correct data for list endpoint', function(assert) {
|
||||||
|
get(this.subject(), 'store').serializerFor(NAME).timestamp = function() {
|
||||||
|
return now;
|
||||||
|
};
|
||||||
return repo(
|
return repo(
|
||||||
'Service',
|
'Service',
|
||||||
'findAllByDatacenter',
|
'findAllByDatacenter',
|
||||||
|
@ -27,6 +32,7 @@ test('findByDatacenter returns the correct data for list endpoint', function(ass
|
||||||
expected(function(payload) {
|
expected(function(payload) {
|
||||||
return payload.map(item =>
|
return payload.map(item =>
|
||||||
Object.assign({}, item, {
|
Object.assign({}, item, {
|
||||||
|
SyncTime: now,
|
||||||
Datacenter: dc,
|
Datacenter: dc,
|
||||||
uid: `["${dc}","${item.Name}"]`,
|
uid: `["${dc}","${item.Name}"]`,
|
||||||
})
|
})
|
||||||
|
@ -69,7 +75,6 @@ test('findBySlug returns the correct data for item endpoint', function(assert) {
|
||||||
service.Nodes = nodes;
|
service.Nodes = nodes;
|
||||||
service.Tags = payload.Nodes[0].Service.Tags;
|
service.Tags = payload.Nodes[0].Service.Tags;
|
||||||
service.meta = {
|
service.meta = {
|
||||||
date: undefined,
|
|
||||||
cursor: undefined,
|
cursor: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { moduleFor, test } from 'ember-qunit';
|
import { moduleFor, test } from 'ember-qunit';
|
||||||
import repo from 'consul-ui/tests/helpers/repo';
|
import repo from 'consul-ui/tests/helpers/repo';
|
||||||
|
import { get } from '@ember/object';
|
||||||
const NAME = 'session';
|
const NAME = 'session';
|
||||||
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
||||||
// Specify the other units that are required for this test.
|
// Specify the other units that are required for this test.
|
||||||
|
@ -8,7 +9,11 @@ moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
||||||
|
|
||||||
const dc = 'dc-1';
|
const dc = 'dc-1';
|
||||||
const id = 'node-name';
|
const id = 'node-name';
|
||||||
|
const now = new Date().getTime();
|
||||||
test('findByNode returns the correct data for list endpoint', function(assert) {
|
test('findByNode returns the correct data for list endpoint', function(assert) {
|
||||||
|
get(this.subject(), 'store').serializerFor(NAME).timestamp = function() {
|
||||||
|
return now;
|
||||||
|
};
|
||||||
return repo(
|
return repo(
|
||||||
'Session',
|
'Session',
|
||||||
'findByNode',
|
'findByNode',
|
||||||
|
@ -27,6 +32,7 @@ test('findByNode returns the correct data for list endpoint', function(assert) {
|
||||||
expected(function(payload) {
|
expected(function(payload) {
|
||||||
return payload.map(item =>
|
return payload.map(item =>
|
||||||
Object.assign({}, item, {
|
Object.assign({}, item, {
|
||||||
|
SyncTime: now,
|
||||||
Datacenter: dc,
|
Datacenter: dc,
|
||||||
uid: `["${dc}","${item.ID}"]`,
|
uid: `["${dc}","${item.ID}"]`,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue