feat: improved expiry retry and error handing

nested pRetry Abort errors can break our retry logic so we need to catch them
pull/2971/head
William Grant 2 years ago
parent 5b6ebcad07
commit 0e67e2a0b7

@ -134,7 +134,7 @@ async function processExpireRequestResponse(
async function expireOnNodes( async function expireOnNodes(
targetNode: Snode, targetNode: Snode,
expireRequest: UpdateExpiryOnNodeSubRequest expireRequest: UpdateExpiryOnNodeSubRequest
): Promise<number | null> { ): Promise<number> {
try { try {
const result = await doSnodeBatchRequest( const result = await doSnodeBatchRequest(
[expireRequest], [expireRequest],
@ -145,12 +145,11 @@ async function expireOnNodes(
); );
if (!result || result.length !== 1) { if (!result || result.length !== 1) {
window?.log?.warn( throw Error(
`WIP: [expireOnNodes] There was an issue with the results. sessionRpc ${targetNode.ip}:${ `There was an issue with the results. sessionRpc ${targetNode.ip}:${
targetNode.port targetNode.port
} expireRequest ${JSON.stringify(expireRequest)}` } expireRequest ${JSON.stringify(expireRequest)}`
); );
return null;
} }
// TODOLATER make sure that this code still works once disappearing messages is merged // TODOLATER make sure that this code still works once disappearing messages is merged
@ -158,55 +157,51 @@ async function expireOnNodes(
const firstResult = result[0]; const firstResult = result[0];
if (firstResult.code !== 200) { if (firstResult.code !== 200) {
window?.log?.warn(`WIP: [expireOnNodes] result is not 200 but ${firstResult.code}`); throw Error(`result is not 200 but ${firstResult.code}`);
return null;
} }
try { const bodyFirstResult = firstResult.body;
const bodyFirstResult = firstResult.body; const expirationResults = await processExpireRequestResponse(
const expirationResults = await processExpireRequestResponse( expireRequest.params.pubkey,
expireRequest.params.pubkey, targetNode,
targetNode, bodyFirstResult.swarm as ExpireMessagesResultsContent,
bodyFirstResult.swarm as ExpireMessagesResultsContent, expireRequest.params.messages
expireRequest.params.messages );
); const firstExpirationResult = Object.entries(expirationResults).at(0);
const firstExpirationResult = Object.entries(expirationResults).at(0); if (!firstExpirationResult) {
if (!firstExpirationResult) { throw new Error('firstExpirationResult is null');
window?.log?.warn( }
'WIP: [expireOnNodes] failed to parse "swarm" result. firstExpirationResult is null'
);
throw new Error('firstExpirationResult is null');
}
const messageHash = firstExpirationResult[0]; const messageHash = firstExpirationResult[0];
const expiry = firstExpirationResult[1].expiry; const expiry = firstExpirationResult[1].expiry;
if (!expiry || !messageHash) { if (!expiry || !messageHash) {
throw new Error( throw new Error(
`Something is wrong with the firstExpirationResult: ${JSON.stringify( `Something is wrong with the firstExpirationResult: ${JSON.stringify(
JSON.stringify(firstExpirationResult) JSON.stringify(firstExpirationResult)
)}` )}`
); );
} }
// window.log.debug( // window.log.debug(
// `WIP: [expireOnNodes] Success!\nHere are the results from one of the snodes.\nmessageHash: ${messageHash} \nexpiry: ${expiry} \nexpires at: ${new Date( // `WIP: [expireOnNodes] Success!\nHere are the results from one of the snodes.\nmessageHash: ${messageHash} \nexpiry: ${expiry} \nexpires at: ${new Date(
// expiry // expiry
// ).toUTCString()}\nnow: ${new Date(GetNetworkTime.getNowWithNetworkOffset()).toUTCString()}` // ).toUTCString()}\nnow: ${new Date(GetNetworkTime.getNowWithNetworkOffset()).toUTCString()}`
// ); // );
return expiry; return expiry;
} catch (e) { } catch (err) {
window?.log?.warn('WIP: [expireOnNodes] Failed to parse "swarm" result: ', e);
}
return null;
} catch (e) {
window?.log?.warn( window?.log?.warn(
'WIP: [expireOnNodes] - send error:', 'WIP: [expireOnNodes]',
e, err.message || err,
`destination ${targetNode.ip}:${targetNode.port}` `destination ${targetNode.ip}:${targetNode.port}`
); );
throw e; // NOTE batch requests have their own retry logic which includes abort errors that will break our retry logic so we need to catch them and throw regular errors
if (err instanceof pRetry.AbortError) {
throw Error(err.message);
}
throw err;
} }
} }
@ -299,38 +294,19 @@ export async function expireMessageOnSnode(
let snode: Snode | undefined; let snode: Snode | undefined;
await pRetry(
async () => {
const swarm = await getSwarmFor(ourPubKey);
snode = sample(swarm);
if (!snode) {
throw new EmptySwarmError(ourPubKey, 'Ran out of swarm nodes to query');
}
},
{
retries: 3,
factor: 2,
minTimeout: SeedNodeAPI.getMinTimeout(),
onFailedAttempt: e => {
window?.log?.warn(
`WIP: [expireMessageOnSnode] get snode attempt #${e.attemptNumber} failed. ${e.retriesLeft} retries left... Error: ${e.message}`
);
},
}
);
try { try {
const expireRequestParams = await buildExpireRequest(props); const expireRequestParams = await buildExpireRequest(props);
if (!expireRequestParams) { if (!expireRequestParams) {
throw new Error(`Failed to build expire request ${JSON.stringify(props)}`); throw new Error(`Failed to build expire request ${JSON.stringify(props)}`);
} }
let newTTL = null; let newTTL = null;
await pRetry( await pRetry(
async () => { async () => {
const swarm = await getSwarmFor(ourPubKey);
snode = sample(swarm);
if (!snode) { if (!snode) {
throw new Error(`No snode found.\n${JSON.stringify(props)}`); throw new EmptySwarmError(ourPubKey, 'Ran out of swarm nodes to query');
} }
newTTL = await expireOnNodes(snode, expireRequestParams); newTTL = await expireOnNodes(snode, expireRequestParams);
}, },
@ -350,9 +326,8 @@ export async function expireMessageOnSnode(
} catch (e) { } catch (e) {
const snodeStr = snode ? `${snode.ip}:${snode.port}` : 'null'; const snodeStr = snode ? `${snode.ip}:${snode.port}` : 'null';
window?.log?.warn( window?.log?.warn(
`WIP: [expireMessageOnSnode] ${e.code ? `${e.code} ` : ''}${ `WIP: [expireMessageOnSnode] ${e.code ? `${e.code} ` : ''}${e.message ||
e.message e} by ${ourPubKey} for ${messageHash} via snode:${snodeStr}`
} by ${ourPubKey} for ${messageHash} via snode:${snodeStr}`
); );
throw e; throw e;
} }

@ -244,7 +244,7 @@ export async function getExpiriesFromSnode(
minTimeout: SeedNodeAPI.getMinTimeout(), minTimeout: SeedNodeAPI.getMinTimeout(),
onFailedAttempt: e => { onFailedAttempt: e => {
window?.log?.warn( window?.log?.warn(
`WIP: [getExpiriesFromSnode] expire message on snode attempt #${e.attemptNumber} failed. ${e.retriesLeft} retries left... Error: ${e.message}` `WIP: [getExpiriesFromSnode] get expiries from snode attempt #${e.attemptNumber} failed. ${e.retriesLeft} retries left... Error: ${e.message}`
); );
}, },
} }

@ -668,25 +668,25 @@ export async function updateMessageExpiryOnSwarm(
expires_at: newTTL, expires_at: newTTL,
}); });
// window.log.debug( window.log.debug(
// `WIP: [updateMessageExpiryOnSwarm] messageHash ${messageHash} has a new TTL of ${newTTL} which expires at ${new Date( `WIP: [updateMessageExpiryOnSwarm] messageHash ${messageHash} has a new TTL of ${newTTL} which expires at ${new Date(
// newTTL newTTL
// ).toUTCString()}` ).toUTCString()}`
// ); );
if (shouldCommit) { if (shouldCommit) {
await message.commit(); await message.commit();
} }
} else { } else {
// window.log.warn( window.log.warn(
// `WIP: [updateMessageExpiryOnSwarm]\nmessageHash ${messageHash} has no new TTL.${ `WIP: [updateMessageExpiryOnSwarm]\nmessageHash ${messageHash} has no new TTL.${
// expiresAt expiresAt
// ? `\nKeeping the old one ${expiresAt}which expires at ${new Date( ? `\nKeeping the old one ${expiresAt}which expires at ${new Date(
// expiresAt expiresAt
// ).toUTCString()}` ).toUTCString()}`
// : '' : ''
// }` }`
// ); );
} }
return message; return message;

Loading…
Cancel
Save