Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added retryFulfilled and retryRejected #2

Merged
merged 8 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ unsubscribe();
```ts
useExecutor(`order-${orderId}`, initialValue, [
// Persists the executor value in the synchronous storage.
syncStorage(localStorage),
synchronizeStorage(localStorage),

// Instantly aborts pending task when executor is deactivated (has no active consumers).
abortDeactivated(),
Expand Down
3 changes: 1 addition & 2 deletions src/main/ExecutorImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export class ExecutorImpl<Value = any> implements Executor {
if (this.isSettled) {
this.isFulfilled = this.isRejected = this.isStale = false;
this.value = this.reason = undefined;
this.timestamp = 0;
this._pubSub.publish({ type: 'cleared', target: this });
}
return this;
Expand Down Expand Up @@ -185,7 +186,6 @@ export class ExecutorImpl<Value = any> implements Executor {
this.isFulfilled = true;
this.isRejected = this.isStale = false;
this.value = value;
this.reason = undefined;
this.timestamp = timestamp;

this._pubSub.publish({ type: 'fulfilled', target: this });
Expand All @@ -203,7 +203,6 @@ export class ExecutorImpl<Value = any> implements Executor {

this.isFulfilled = this.isStale = false;
this.isRejected = true;
this.value = undefined;
this.reason = reason;
this.timestamp = timestamp;

Expand Down
9 changes: 4 additions & 5 deletions src/main/plugin/abortDeactivated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ export default function abortDeactivated(ms = 0): ExecutorPlugin {

executor.subscribe(event => {
switch (event.type) {
case 'activated':
case 'disposed':
clearTimeout(timer);
break;

case 'deactivated':
clearTimeout(timer);

timer = setTimeout(() => {
executor.abort();
}, ms);
break;

case 'activated':
clearTimeout(timer);
break;
}
});
};
Expand Down
11 changes: 5 additions & 6 deletions src/main/plugin/disposeDeactivated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,23 @@ import type { ExecutorPlugin } from '../types';
*
* @param ms The timeout in milliseconds after which the executor is disposed.
*/
export default function disposeDeactivated(ms = 0): ExecutorPlugin {
export default function disposeDeactivated(ms = 5_000): ExecutorPlugin {
return executor => {
let timer: NodeJS.Timeout;

executor.subscribe(event => {
switch (event.type) {
case 'activated':
case 'disposed':
clearTimeout(timer);
break;

case 'deactivated':
clearTimeout(timer);

timer = setTimeout(() => {
executor.manager.dispose(executor.key);
}, ms);
break;

case 'activated':
clearTimeout(timer);
break;
}
});
};
Expand Down
17 changes: 10 additions & 7 deletions src/main/plugin/invalidateAfter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ export default function invalidateAfter(ms: number): ExecutorPlugin {

executor.subscribe(event => {
switch (event.type) {
case 'activated':
case 'fulfilled':
case 'rejected':
clearTimeout(timer);

timer = setTimeout(
() => {
executor.invalidate();
},
ms - Date.now() + executor.timestamp
);
if (!executor.isPending && executor.isActive && executor.isSettled) {
timer = setTimeout(
() => {
executor.invalidate();
},
ms - Date.now() + executor.timestamp
);
}
break;

case 'disposed':
case 'deactivated':
clearTimeout(timer);
break;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/plugin/invalidateByPeers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import type { ExecutorPlugin } from '../types';
export default function invalidateByPeers(keys: Array<RegExp | string>): ExecutorPlugin {
return executor => {
const unsubscribe = executor.manager.subscribe(event => {
const targetKey = event.target.key;
const peerKey = event.target.key;

if (
(event.type === 'invalidated' || event.type === 'fulfilled') &&
keys.some(key => (typeof key === 'string' ? key === targetKey : key.test(targetKey)))
keys.some(key => (typeof key === 'string' ? key === peerKey : key.test(peerKey)))
) {
executor.invalidate();
}
Expand Down
18 changes: 11 additions & 7 deletions src/main/plugin/retryFocused.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,22 @@ const plugin: ExecutorPlugin = executor => {
}

const handleFocus = () => {
if (window.document.visibilityState === 'visible' && executor.isActive) {
if (window.document.visibilityState === 'visible') {
executor.retry();
}
};

window.addEventListener('visibilitychange', handleFocus, false);
window.addEventListener('focus', handleFocus, false);

executor.subscribe(event => {
if (event.type === 'disposed') {
window.removeEventListener('visibilitychange', handleFocus, false);
window.removeEventListener('focus', handleFocus, false);
switch (event.type) {
case 'activated':
window.addEventListener('visibilitychange', handleFocus, false);
window.addEventListener('focus', handleFocus, false);
break;

case 'deactivated':
window.removeEventListener('visibilitychange', handleFocus, false);
window.removeEventListener('focus', handleFocus, false);
break;
}
});
};
44 changes: 44 additions & 0 deletions src/main/plugin/retryFulfilled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Executor, ExecutorPlugin } from '../types';

/**
* Repeats the last task after the execution was fulfilled.
*
* @param count The number of repetitions.
* @param ms The delay in milliseconds after which the repetition is scheduled.
* @template Value The value stored by the executor.
*/
export default function retryFulfilled<Value = any>(
count = Infinity,
ms: number | ((index: number, executor: Executor<Value>) => number) = 5_000
): ExecutorPlugin<Value> {
return executor => {
let timer: NodeJS.Timeout;
let index = 0;

executor.subscribe(event => {
switch (event.type) {
case 'activated':
case 'fulfilled':
clearTimeout(timer);

if (!executor.isPending && executor.isActive && executor.isFulfilled && index < count) {
timer = setTimeout(
() => {
index++;
executor.retry();
},
(typeof ms === 'function' ? ms(index, executor) : ms) - Date.now() + executor.timestamp
);
}
break;

case 'rejected':
case 'aborted':
case 'deactivated':
index = 0;
clearTimeout(timer);
break;
}
});
};
}
48 changes: 48 additions & 0 deletions src/main/plugin/retryRejected.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Executor, ExecutorPlugin } from '../types';

/**
* Retries the last task after the execution has failed.
*
* @param count The number of times the task must be repeated if rejected.
* @param ms The delay in milliseconds after which the retry is scheduled.
* @template Value The value stored by the executor.
*/
export default function retryRejected<Value = any>(
count = 3,
ms: number | ((index: number, executor: Executor<Value>) => number) = exponentialDelay
): ExecutorPlugin<Value> {
return executor => {
let timer: NodeJS.Timeout;
let index = 0;

executor.subscribe(event => {
switch (event.type) {
case 'activated':
case 'rejected':
clearTimeout(timer);

if (!executor.isPending && executor.isActive && executor.isRejected && index < count) {
timer = setTimeout(
() => {
index++;
executor.retry();
},
(typeof ms === 'function' ? ms(index, executor) : ms) - Date.now() + executor.timestamp
);
}
break;

case 'fulfilled':
case 'aborted':
case 'deactivated':
index = 0;
clearTimeout(timer);
break;
}
});
};
}

function exponentialDelay(index: number): number {
return 1000 * 1.8 ** index;
}
4 changes: 0 additions & 4 deletions src/main/plugin/retryStale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ export default function retryStale(): ExecutorPlugin {
}

const plugin: ExecutorPlugin = executor => {
if (executor.isStale) {
executor.retry();
}

executor.subscribe(event => {
if ((event.type === 'invalidated' && executor.isActive) || (event.type === 'activated' && executor.isStale)) {
executor.retry();
Expand Down
91 changes: 0 additions & 91 deletions src/main/plugin/syncStorage.ts

This file was deleted.

Loading