Skip to content

Commit

Permalink
fix: error not being set if get failed without retry
Browse files Browse the repository at this point in the history
  • Loading branch information
jmeistrich committed Sep 20, 2024
1 parent 6c3104e commit 2d21a36
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 40 deletions.
80 changes: 42 additions & 38 deletions src/sync/retry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,46 +28,50 @@ export function runWithRetry<T>(
fn: (params: OnErrorRetryParams) => T | Promise<T>,
onError: (error: Error, retryParams: OnErrorRetryParams) => void,
): T | Promise<T> {
let value = fn(state);
try {
let value = fn(state);

if (isPromise(value) && retryOptions) {
let timeoutRetry: number;
if (mapRetryTimeouts.has(state.node)) {
clearTimeout(mapRetryTimeouts.get(state.node));
}
return new Promise<any>((resolve, reject) => {
const run = () => {
(value as Promise<any>)
.then((val: any) => {
resolve(val);
})
.catch((error: Error) => {
state.retryNum++;
if (timeoutRetry) {
clearTimeout(timeoutRetry);
}
if (onError) {
onError(error, state);
}
if (!state.cancelRetry) {
const timeout = createRetryTimeout(retryOptions, state.retryNum, () => {
value = fn(state);
run();
});
if (isPromise(value) && retryOptions) {
let timeoutRetry: number;
if (mapRetryTimeouts.has(state.node)) {
clearTimeout(mapRetryTimeouts.get(state.node));
}
return new Promise<any>((resolve, reject) => {
const run = () => {
(value as Promise<any>)
.then((val: any) => {
resolve(val);
})
.catch((error: Error) => {
state.retryNum++;
if (timeoutRetry) {
clearTimeout(timeoutRetry);
}
if (onError) {
onError(error, state);
}
if (!state.cancelRetry) {
const timeout = createRetryTimeout(retryOptions, state.retryNum, () => {
value = fn(state);
run();
});

if (timeout === false) {
state.cancelRetry = true;
reject(error);
} else {
mapRetryTimeouts.set(state.node, timeout);
timeoutRetry = timeout;
if (timeout === false) {
state.cancelRetry = true;
reject(error);
} else {
mapRetryTimeouts.set(state.node, timeout);
timeoutRetry = timeout;
}
}
}
});
};
run();
});
}
});
};
run();
});
}

return value;
return value;
} catch (error) {
return Promise.reject(error);
}
}
6 changes: 4 additions & 2 deletions src/sync/syncObservable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,9 @@ export function syncObservable<T>(
}
const existingValue = getNodeValue(node);

const onError = (error: Error) => onGetError(error, { getParams, source: 'get' });
const onError = (error: Error) => {
onGetError(error, { getParams, source: 'get' });
};

const getParams: SyncedGetParams<T> = {
node,
Expand Down Expand Up @@ -1211,7 +1213,7 @@ export function syncObservable<T>(
});
};
if (isPromise(got)) {
got.then(handle);
got.then(handle).catch(onError);
} else {
handle(got);
}
Expand Down
34 changes: 34 additions & 0 deletions tests/crud.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2540,3 +2540,37 @@ describe('waitForSet', () => {
expect(typeAtWaitForSet).toEqual('create');
});
});
describe('Error is set', () => {
test('error is set if get fails', async () => {
const obs$ = observable<BasicValue>(
syncedCrud({
get: () => {
// await promiseTimeout(1);
throw new Error('test');
},
}),
);

obs$.get();

await promiseTimeout(1);

expect(syncState(obs$).error.get()).toEqual(new Error('test'));
});
test('error is set if get fails async', async () => {
const obs$ = observable<BasicValue>(
syncedCrud({
get: async () => {
await promiseTimeout(1);
throw new Error('test');
},
}),
);

obs$.get();

await promiseTimeout(2);

expect(syncState(obs$).error.get()).toEqual(new Error('test'));
});
});

0 comments on commit 2d21a36

Please sign in to comment.