57f4e9a62e
This was a disturbing discovery. Requests in watch loops would recycle AbortControllers meaning once any request was aborted, all requests forever after were skipped. I noticed it with deployments and job summary on the job detail page. I suspect this regression occurred when jQuery was removed. This needs test coverage still to make sure it doesn't happen again.
121 lines
3.3 KiB
JavaScript
121 lines
3.3 KiB
JavaScript
import Ember from 'ember';
|
|
import { get } from '@ember/object';
|
|
import { assert } from '@ember/debug';
|
|
import RSVP from 'rsvp';
|
|
import { task } from 'ember-concurrency';
|
|
import { AbortController } from 'fetch';
|
|
import wait from 'nomad-ui/utils/wait';
|
|
import Watchable from 'nomad-ui/adapters/watchable';
|
|
import config from 'nomad-ui/config/environment';
|
|
|
|
const isEnabled = config.APP.blockingQueries !== false;
|
|
|
|
export function watchRecord(modelName) {
|
|
return task(function*(id, throttle = 2000) {
|
|
assert(
|
|
'To watch a record, the record adapter MUST extend Watchable',
|
|
this.store.adapterFor(modelName) instanceof Watchable
|
|
);
|
|
if (typeof id === 'object') {
|
|
id = get(id, 'id');
|
|
}
|
|
while (isEnabled && !Ember.testing) {
|
|
const controller = new AbortController();
|
|
try {
|
|
yield RSVP.all([
|
|
this.store.findRecord(modelName, id, {
|
|
reload: true,
|
|
adapterOptions: { watch: true, abortController: controller },
|
|
}),
|
|
wait(throttle),
|
|
]);
|
|
} catch (e) {
|
|
yield e;
|
|
break;
|
|
} finally {
|
|
controller.abort();
|
|
}
|
|
}
|
|
}).drop();
|
|
}
|
|
|
|
export function watchRelationship(relationshipName) {
|
|
return task(function*(model, throttle = 2000) {
|
|
assert(
|
|
'To watch a relationship, the adapter of the model provided to the watchRelationship task MUST extend Watchable',
|
|
this.store.adapterFor(model.constructor.modelName) instanceof Watchable
|
|
);
|
|
while (isEnabled && !Ember.testing) {
|
|
const controller = new AbortController();
|
|
try {
|
|
yield RSVP.all([
|
|
this.store
|
|
.adapterFor(model.constructor.modelName)
|
|
.reloadRelationship(model, relationshipName, {
|
|
watch: true,
|
|
abortController: controller,
|
|
}),
|
|
wait(throttle),
|
|
]);
|
|
} catch (e) {
|
|
yield e;
|
|
break;
|
|
} finally {
|
|
controller.abort();
|
|
}
|
|
}
|
|
}).drop();
|
|
}
|
|
|
|
export function watchAll(modelName) {
|
|
return task(function*(throttle = 2000) {
|
|
assert(
|
|
'To watch all, the respective adapter MUST extend Watchable',
|
|
this.store.adapterFor(modelName) instanceof Watchable
|
|
);
|
|
while (isEnabled && !Ember.testing) {
|
|
const controller = new AbortController();
|
|
try {
|
|
yield RSVP.all([
|
|
this.store.findAll(modelName, {
|
|
reload: true,
|
|
adapterOptions: { watch: true, abortController: controller },
|
|
}),
|
|
wait(throttle),
|
|
]);
|
|
} catch (e) {
|
|
yield e;
|
|
break;
|
|
} finally {
|
|
controller.abort();
|
|
}
|
|
}
|
|
}).drop();
|
|
}
|
|
|
|
export function watchQuery(modelName) {
|
|
return task(function*(params, throttle = 10000) {
|
|
assert(
|
|
'To watch a query, the adapter for the type being queried MUST extend Watchable',
|
|
this.store.adapterFor(modelName) instanceof Watchable
|
|
);
|
|
while (isEnabled && !Ember.testing) {
|
|
const controller = new AbortController();
|
|
try {
|
|
yield RSVP.all([
|
|
this.store.query(modelName, params, {
|
|
reload: true,
|
|
adapterOptions: { watch: true, abortController: controller },
|
|
}),
|
|
wait(throttle),
|
|
]);
|
|
} catch (e) {
|
|
yield e;
|
|
break;
|
|
} finally {
|
|
controller.abort();
|
|
}
|
|
}
|
|
}).drop();
|
|
}
|