Skip to content

Commit 89e9e59

Browse files
Bring sendCommandWithRetry to the main back end code.
1 parent b80ebe6 commit 89e9e59

File tree

1 file changed

+45
-15
lines changed

1 file changed

+45
-15
lines changed

api/abstractplay.ts

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,32 @@ type StandingChallengeRec = {
404404
standing: StandingChallenge[];
405405
};
406406

407+
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
408+
409+
async function sendCommandWithRetry(command: any, maxRetries = 8, initialDelay = 100, maxDelay = 5000) {
410+
let retries = 0;
411+
while (retries < maxRetries) {
412+
try {
413+
// @ts-ignore
414+
return await ddbDocClient.send(command);
415+
} catch (err: any) {
416+
if (['ThrottlingException', 'ProvisionedThroughputExceededException', 'InternalServerError', 'ServiceUnavailable'].includes(err.name)) {
417+
retries++;
418+
if (retries >= maxRetries) {
419+
console.error(`Command failed after ${maxRetries} retries.`);
420+
throw err;
421+
}
422+
const delay = Math.min(initialDelay * Math.pow(2, retries - 1), maxDelay);
423+
const jitter = delay * 0.1 * Math.random();
424+
console.log(`Retryable error (${err.name}) caught. Retrying in ${Math.round(delay + jitter)}ms...`);
425+
await sleep(delay + jitter);
426+
} else {
427+
throw err;
428+
}
429+
}
430+
}
431+
}
432+
407433
module.exports.query = async (event: { queryStringParameters: any; }) => {
408434
console.log(event);
409435
const pars = event.queryStringParameters;
@@ -1641,7 +1667,7 @@ async function updateUserGames(userId: string, gamesUpdate: undefined | number,
16411667
gameIDsChanged.length = 0;
16421668
if (gamesUpdate === undefined) {
16431669
// Update "old" users. This is a one-time update.
1644-
return ddbDocClient.send(new UpdateCommand({
1670+
return sendCommandWithRetry(new UpdateCommand({
16451671
TableName: process.env.ABSTRACT_PLAY_TABLE,
16461672
Key: { "pk": "USER", "sk": userId },
16471673
ExpressionAttributeValues: { ":val": 1, ":gs": games },
@@ -1650,7 +1676,7 @@ async function updateUserGames(userId: string, gamesUpdate: undefined | number,
16501676
} else {
16511677
console.log(`updateUserGames: optimistically updating games for ${userId}`);
16521678
try {
1653-
await ddbDocClient.send(new UpdateCommand({
1679+
await sendCommandWithRetry(new UpdateCommand({
16541680
TableName: process.env.ABSTRACT_PLAY_TABLE,
16551681
Key: { "pk": "USER", "sk": userId },
16561682
ExpressionAttributeValues: { ":val": gamesUpdate, ":inc": 1, ":gs": games },
@@ -1688,21 +1714,25 @@ async function updateUserGames(userId: string, gamesUpdate: undefined | number,
16881714
}
16891715
try {
16901716
console.log(`updateUserGames: Update ${count} of games for user`, userId, newgames);
1691-
await ddbDocClient.send(new UpdateCommand({
1717+
await sendCommandWithRetry(new UpdateCommand({
16921718
TableName: process.env.ABSTRACT_PLAY_TABLE,
16931719
Key: { "pk": "USER", "sk": userId },
16941720
ExpressionAttributeValues: { ":val": gamesUpdate, ":inc": 1, ":gs": newgames },
16951721
ConditionExpression: "gamesUpdate = :val",
16961722
UpdateExpression: "set gamesUpdate = gamesUpdate + :inc, games = :gs"
16971723
}));
16981724
return;
1699-
} catch (err: any) {
1700-
count++;
1725+
} catch (innerErr: any) {
1726+
if (innerErr.name === 'ConditionalCheckFailedException') {
1727+
count++;
1728+
} else {
1729+
throw innerErr;
1730+
}
17011731
}
17021732
}
1703-
new Error(`updateUserGames: Unable to update games for user ${userId} after 3 retries`);
1733+
throw new Error(`updateUserGames: Unable to update games for user ${userId} after 3 retries`);
17041734
} else {
1705-
new Error(err);
1735+
throw err;
17061736
}
17071737
}
17081738
}
@@ -2900,29 +2930,29 @@ function addToGameLists(type: string, game: Game, now: number, keepgame: boolean
29002930
const work: Promise<any>[] = [];
29012931
const sk = now + "#" + game.id;
29022932
if (type === "COMPLETEDGAMES" && keepgame) {
2903-
work.push(ddbDocClient.send(new PutCommand({
2933+
work.push(sendCommandWithRetry(new PutCommand({
29042934
TableName: process.env.ABSTRACT_PLAY_TABLE,
29052935
Item: {
29062936
"pk": type,
29072937
"sk": sk,
29082938
...game}
29092939
})));
2910-
work.push(ddbDocClient.send(new PutCommand({
2940+
work.push(sendCommandWithRetry(new PutCommand({
29112941
TableName: process.env.ABSTRACT_PLAY_TABLE,
29122942
Item: {
29132943
"pk": type + "#" + game.metaGame,
29142944
"sk": sk,
29152945
...game}
29162946
})));
29172947
game.players.forEach((player: { id: string; }) => {
2918-
work.push(ddbDocClient.send(new PutCommand({
2948+
work.push(sendCommandWithRetry(new PutCommand({
29192949
TableName: process.env.ABSTRACT_PLAY_TABLE,
29202950
Item: {
29212951
"pk": type + "#" + player.id,
29222952
"sk": sk,
29232953
...game}
29242954
})));
2925-
work.push(ddbDocClient.send(new PutCommand({
2955+
work.push(sendCommandWithRetry(new PutCommand({
29262956
TableName: process.env.ABSTRACT_PLAY_TABLE,
29272957
Item: {
29282958
"pk": type + "#" + game.metaGame + "#" + player.id,
@@ -2932,7 +2962,7 @@ function addToGameLists(type: string, game: Game, now: number, keepgame: boolean
29322962
});
29332963
}
29342964
if (type === "CURRENTGAMES") {
2935-
work.push(ddbDocClient.send(new UpdateCommand({
2965+
work.push(sendCommandWithRetry(new UpdateCommand({
29362966
TableName: process.env.ABSTRACT_PLAY_TABLE,
29372967
Key: { "pk": "METAGAMES", "sk": "COUNTS" },
29382968
ExpressionAttributeNames: { "#g": game.metaGame },
@@ -2946,7 +2976,7 @@ function addToGameLists(type: string, game: Game, now: number, keepgame: boolean
29462976
update += ", #g.completedgames :n";
29472977
eavObj[":n"] = 1
29482978
}
2949-
work.push(ddbDocClient.send(new UpdateCommand({
2979+
work.push(sendCommandWithRetry(new UpdateCommand({
29502980
TableName: process.env.ABSTRACT_PLAY_TABLE,
29512981
Key: { "pk": "METAGAMES", "sk": "COUNTS" },
29522982
ExpressionAttributeNames: { "#g": game.metaGame },
@@ -6542,7 +6572,7 @@ async function eventCreateGames(userid: string, pars: {eventid: string; pairs: P
65426572
}
65436573
}
65446574
// queue for update
6545-
const addGame = ddbDocClient.send(new PutCommand({
6575+
const addGame = sendCommandWithRetry(new PutCommand({
65466576
TableName: process.env.ABSTRACT_PLAY_TABLE,
65476577
Item: {
65486578
"pk": "GAME",
@@ -6599,7 +6629,7 @@ async function eventCreateGames(userid: string, pars: {eventid: string; pairs: P
65996629
player2: pair.p2.id,
66006630
};
66016631
list.push(
6602-
ddbDocClient.send(new PutCommand({
6632+
sendCommandWithRetry(new PutCommand({
66036633
TableName: process.env.ABSTRACT_PLAY_TABLE,
66046634
Item: eventGame,
66056635
}))

0 commit comments

Comments
 (0)