Skip to content
This repository has been archived by the owner on Feb 9, 2022. It is now read-only.

Commit

Permalink
fix(memoized-task): now canceled tasks are automatically retried
Browse files Browse the repository at this point in the history
A canceled task could occur if your component is torn down before the
task completes. For long running tasks (such as those network-bound),
this can be a big problem, because the task will become cached, and
the next time a component is mounted that wants to access that same
network resource, no remote request would occur because the canceled
task was cached.

Now, canceled tasks bust the cache, allowing quick navigations or
quick remounts to correctly re-fetch network resources (or whatever
the long running async task is)
  • Loading branch information
NullVoxPopuli committed Apr 22, 2021
1 parent 5ede2c6 commit 0ce0373
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 24 deletions.
19 changes: 17 additions & 2 deletions addon/-private/memoized-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Resource } from 'ember-could-get-used-to-this';
import { action } from '@ember/object';
import { assert } from '@ember/debug';
import { getOwner } from '@ember/application';
import { DEBUG } from '@glimmer/env';

import { taskFor } from 'ember-concurrency-ts';
import { task } from 'ember-concurrency-decorators';
Expand All @@ -21,6 +22,9 @@ interface Args<Return, TaskArgs extends CacheableArgs> {

const CACHE = 'service:ember-resource-tasks/-private/do-not-use/arg-cache';

export const TASK_PROPERTY = Symbol('TASK');
export const TASK_INSTANCE_FROM_CACHE = Symbol('TASK_FROM_CACHE');

/**
* Whenever any args change *value*, the task will re run
* All args must be stringish
Expand All @@ -45,15 +49,26 @@ export class MemoizedTask<Return, TaskArgs extends CacheableArgs> extends Resour
consumeTag(task, 'isFinished');
consumeTag(task, 'error');

return { ...extractTaskData(task), retry: this._perform };
let result = { ...extractTaskData(task), retry: this._perform };

if (DEBUG) {
(result as any)[TASK_INSTANCE_FROM_CACHE] = task;
(result as any)[TASK_PROPERTY] = task;
}

return result;
}

private get cacheKey() {
return toCacheKey(...this.args.named.args);
}

private get needsUpdate() {
return !this.cacheBucket.has(this.cacheKey);
if (!this.cacheBucket.has(this.cacheKey)) {
return true;
}

return this.cacheBucket.get(this.cacheKey)?.isCanceled;
}

get _task() {
Expand Down
1 change: 1 addition & 0 deletions addon/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"paths": {
"ember-resource-tasks": ["."],
"ember-resource-tasks/*": ["./*"],
"@ember/destroyable": ["node_modules/ember-destroyable-polyfill"],
"*": ["../types"]
}
},
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"ember-concurrency-decorators": "^2.0.3",
"ember-concurrency-ts": "^0.2.2",
"ember-could-get-used-to-this": "^1.0.1",
"ember-destroyable-polyfill": "^2.0.3",
"ember-test-waiters": "^2.1.3"
},
"devDependencies": {
Expand Down
31 changes: 31 additions & 0 deletions tests/integration/resources/memoized-task-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import { setupTest } from 'ember-qunit';
import { setOwner } from '@ember/application';
import { settled } from '@ember/test-helpers';
import { waitFor } from '@ember/test-waiters';
import { destroy } from '@ember/destroyable';

import { MemoizedTask, valueFor } from 'ember-resource-tasks';
import { consumeTag } from 'ember-resource-tasks/-private/utils';
import { TASK_INSTANCE_FROM_CACHE } from 'ember-resource-tasks/-private/memoized-task';

import type ApplicationInstance from '@ember/application/instance';

Expand Down Expand Up @@ -113,4 +115,33 @@ module('Integration | Resource | MemoizedTask', function (hooks) {
assert.equal(subject2.data.value, 5, 'the cache bucket transfers to other instances');
assert.equal(invocations, 3, 'value used is from cache and not recomputed');
});

test(`a canceled task in the cache is ignored`, async function (assert) {
let subject = create(this.owner);

assert.equal(invocations, 0);
assert.equal(subject.data.value, undefined);

let taskInstance = (subject.data as any)[TASK_INSTANCE_FROM_CACHE];

destroy(subject);

await settled();

assert.equal(taskInstance.isCanceled, true, 'task is cancelled');
assert.equal(invocations, 1);

let subject2 = create(this.owner);

assert.equal(subject2.data.value, undefined);

await settled();

taskInstance = (subject2.data as any)[TASK_INSTANCE_FROM_CACHE];

assert.equal(taskInstance.isCanceled, false, 'task is not cancelled');

assert.equal(subject2.data.value, 1);
assert.equal(invocations, 2);
});
});
27 changes: 5 additions & 22 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5385,7 +5385,7 @@ debug@~4.1.0:
dependencies:
ms "^2.1.1"

debuglog@*, debuglog@^1.0.1:
debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
Expand Down Expand Up @@ -8392,7 +8392,7 @@ import-lazy@^2.1.0:
resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=

imurmurhash@*, imurmurhash@^0.1.4:
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
Expand Down Expand Up @@ -9575,11 +9575,6 @@ lodash._baseflatten@^3.0.0:
lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0"

lodash._baseindexof@*:
version "3.1.0"
resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=

lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
Expand All @@ -9588,16 +9583,11 @@ lodash._baseuniq@~4.6.0:
lodash._createset "~4.0.0"
lodash._root "~3.0.0"

lodash._bindcallback@*, lodash._bindcallback@^3.0.0:
lodash._bindcallback@^3.0.0:
version "3.0.1"
resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=

lodash._cacheindexof@*:
version "3.0.2"
resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=

lodash._createassigner@^3.0.0:
version "3.1.1"
resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11"
Expand All @@ -9607,19 +9597,12 @@ lodash._createassigner@^3.0.0:
lodash._isiterateecall "^3.0.0"
lodash.restparam "^3.0.0"

lodash._createcache@*:
version "3.1.2"
resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
dependencies:
lodash._getnative "^3.0.0"

lodash._createset@~4.0.0:
version "4.0.3"
resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=

lodash._getnative@*, lodash._getnative@^3.0.0:
lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
Expand Down Expand Up @@ -9757,7 +9740,7 @@ lodash.omit@^4.1.0:
resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60"
integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=

lodash.restparam@*, lodash.restparam@^3.0.0:
lodash.restparam@^3.0.0:
version "3.6.1"
resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
Expand Down

0 comments on commit 0ce0373

Please sign in to comment.