Skip to content

Commit 8994f8b

Browse files
committed
Apologies for my ass backwards workflow!
1 parent bf41d39 commit 8994f8b

File tree

1 file changed

+54
-24
lines changed

1 file changed

+54
-24
lines changed

utils/starttournaments.ts

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,32 @@ const headers = {
3535
'Access-Control-Allow-Origin': '*'
3636
};
3737

38+
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
39+
40+
async function sendCommandWithRetry(command: any, maxRetries = 8, initialDelay = 100, maxDelay = 5000) {
41+
let retries = 0;
42+
while (retries < maxRetries) {
43+
try {
44+
// @ts-ignore
45+
return await ddbDocClient.send(command);
46+
} catch (err: any) {
47+
if (['ThrottlingException', 'ProvisionedThroughputExceededException', 'InternalServerError', 'ServiceUnavailable'].includes(err.name)) {
48+
retries++;
49+
if (retries >= maxRetries) {
50+
console.error(`Command failed after ${maxRetries} retries.`);
51+
throw err;
52+
}
53+
const delay = Math.min(initialDelay * Math.pow(2, retries - 1), maxDelay);
54+
const jitter = delay * 0.1 * Math.random();
55+
console.log(`Retryable error (${err.name}) caught. Retrying in ${Math.round(delay + jitter)}ms...`);
56+
await sleep(delay + jitter);
57+
} else {
58+
throw err;
59+
}
60+
}
61+
}
62+
}
63+
3864
// Types
3965
export type UserSettings = {
4066
[k: string]: any;
@@ -234,7 +260,7 @@ async function getPlayersSlowly(playerIDs: string[]) {
234260
const players: FullUser[] = [];
235261
for (const id of playerIDs) {
236262
try {
237-
const playerData = await ddbDocClient.send(
263+
const playerData = await sendCommandWithRetry(
238264
new GetCommand({
239265
TableName: process.env.ABSTRACT_PLAY_TABLE,
240266
Key: {
@@ -255,29 +281,29 @@ function addToGameLists(type: string, game: Game, now: number, keepgame: boolean
255281
const work: Promise<any>[] = [];
256282
const sk = now + "#" + game.id;
257283
if (type === "COMPLETEDGAMES" && keepgame) {
258-
work.push(ddbDocClient.send(new PutCommand({
284+
work.push(sendCommandWithRetry(new PutCommand({
259285
TableName: process.env.ABSTRACT_PLAY_TABLE,
260286
Item: {
261287
"pk": type,
262288
"sk": sk,
263289
...game}
264290
})));
265-
work.push(ddbDocClient.send(new PutCommand({
291+
work.push(sendCommandWithRetry(new PutCommand({
266292
TableName: process.env.ABSTRACT_PLAY_TABLE,
267293
Item: {
268294
"pk": type + "#" + game.metaGame,
269295
"sk": sk,
270296
...game}
271297
})));
272298
game.players.forEach((player: { id: string; }) => {
273-
work.push(ddbDocClient.send(new PutCommand({
299+
work.push(sendCommandWithRetry(new PutCommand({
274300
TableName: process.env.ABSTRACT_PLAY_TABLE,
275301
Item: {
276302
"pk": type + "#" + player.id,
277303
"sk": sk,
278304
...game}
279305
})));
280-
work.push(ddbDocClient.send(new PutCommand({
306+
work.push(sendCommandWithRetry(new PutCommand({
281307
TableName: process.env.ABSTRACT_PLAY_TABLE,
282308
Item: {
283309
"pk": type + "#" + game.metaGame + "#" + player.id,
@@ -287,7 +313,7 @@ function addToGameLists(type: string, game: Game, now: number, keepgame: boolean
287313
});
288314
}
289315
if (type === "CURRENTGAMES") {
290-
work.push(ddbDocClient.send(new UpdateCommand({
316+
work.push(sendCommandWithRetry(new UpdateCommand({
291317
TableName: process.env.ABSTRACT_PLAY_TABLE,
292318
Key: { "pk": "METAGAMES", "sk": "COUNTS" },
293319
ExpressionAttributeNames: { "#g": game.metaGame },
@@ -301,7 +327,7 @@ function addToGameLists(type: string, game: Game, now: number, keepgame: boolean
301327
update += ", #g.completedgames :n";
302328
eavObj[":n"] = 1
303329
}
304-
work.push(ddbDocClient.send(new UpdateCommand({
330+
work.push(sendCommandWithRetry(new UpdateCommand({
305331
TableName: process.env.ABSTRACT_PLAY_TABLE,
306332
Key: { "pk": "METAGAMES", "sk": "COUNTS" },
307333
ExpressionAttributeNames: { "#g": game.metaGame },
@@ -352,7 +378,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
352378
// Cancel tournament. Everyone is gone.
353379
try {
354380
console.log(`Deleting tournament ${tournament.id}`);
355-
await ddbDocClient.send(
381+
await sendCommandWithRetry(
356382
new DeleteCommand({
357383
TableName: process.env.ABSTRACT_PLAY_TABLE,
358384
Key: {
@@ -361,7 +387,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
361387
},
362388
}));
363389
const sk = tournament.metaGame + "#" + tournament.variants.sort().join("|");
364-
await ddbDocClient.send(
390+
await sendCommandWithRetry(
365391
new UpdateCommand({
366392
TableName: process.env.ABSTRACT_PLAY_TABLE,
367393
Key: {"pk": "TOURNAMENTSCOUNTER", "sk": sk},
@@ -417,7 +443,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
417443
if (tournament.waiting !== true) {
418444
try {
419445
console.log(`Updating tournament ${tournament.id} to waiting`);
420-
await ddbDocClient.send(new UpdateCommand({
446+
await sendCommandWithRetry(new UpdateCommand({
421447
TableName: process.env.ABSTRACT_PLAY_TABLE,
422448
Key: { "pk": "TOURNAMENT", "sk": tournament.id },
423449
ExpressionAttributeValues: { ":t": true },
@@ -463,7 +489,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
463489
player.sk = tournament.id + "#" + division.toString() + '#' + player.playerid;
464490
try {
465491
console.log(`Adding player ${player.playerid} to tournament ${tournament.id} in division ${division}`);
466-
await ddbDocClient.send(new PutCommand({
492+
await sendCommandWithRetry(new PutCommand({
467493
TableName: process.env.ABSTRACT_PLAY_TABLE,
468494
Item: player
469495
}));
@@ -476,7 +502,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
476502
if (division > 1) {
477503
try {
478504
console.log(`Deleting player ${player.playerid} from tournament ${tournament.id} with division 1 (so they can be put in the right division)`);
479-
await ddbDocClient.send(new DeleteCommand({
505+
await sendCommandWithRetry(new DeleteCommand({
480506
TableName: process.env.ABSTRACT_PLAY_TABLE,
481507
Key: {
482508
"pk": "TOURNAMENTPLAYER", "sk": tournament.id + "#1#" + player.playerid
@@ -537,7 +563,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
537563
const state = engine.serialize();
538564
try {
539565
console.log(`Creating game ${gameId} for tournament ${tournament.id} with division ${division}`);
540-
await ddbDocClient.send(new PutCommand({
566+
await sendCommandWithRetry(new PutCommand({
541567
TableName: process.env.ABSTRACT_PLAY_TABLE,
542568
Item: {
543569
"pk": "GAME",
@@ -588,7 +614,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
588614
"player2": gamePlayers[1].id
589615
};
590616
console.log(`Adding game ${gameId} to TOURNAMENTGAME list`);
591-
await ddbDocClient.send(new PutCommand({
617+
await sendCommandWithRetry(new PutCommand({
592618
TableName: process.env.ABSTRACT_PLAY_TABLE,
593619
Item: tournamentGame
594620
}));
@@ -607,7 +633,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
607633
}
608634
const newTournamentid = uuid();
609635
console.log(`Updating tournament ${tournament.id} to started`);
610-
await ddbDocClient.send(new UpdateCommand({
636+
await sendCommandWithRetry(new UpdateCommand({
611637
TableName: process.env.ABSTRACT_PLAY_TABLE,
612638
Key: { "pk": "TOURNAMENT", "sk": tournament.id },
613639
ExpressionAttributeValues: { ":dt": now, ":t": true, ":nextid": newTournamentid, ":ds": divisions },
@@ -616,7 +642,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
616642
// open next tournament for sign-up.
617643
console.log(`Opening next tournament ${newTournamentid} for sign-up. Update TOURNAMENTSCOUNTER for '${tournament.metaGame}#${tournament.variants.sort().join("|")}'`);
618644
try {
619-
await ddbDocClient.send(new UpdateCommand({
645+
await sendCommandWithRetry(new UpdateCommand({
620646
TableName: process.env.ABSTRACT_PLAY_TABLE,
621647
Key: { "pk": "TOURNAMENTSCOUNTER", "sk": tournament.metaGame + "#" + tournament.variants.sort().join("|") },
622648
ExpressionAttributeValues: { ":inc": 1, ":f": false },
@@ -641,7 +667,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
641667
};
642668
console.log(`Creating new tournament ${newTournamentid}`);
643669
try {
644-
await ddbDocClient.send(new PutCommand({
670+
await sendCommandWithRetry(new PutCommand({
645671
TableName: process.env.ABSTRACT_PLAY_TABLE,
646672
Item: data
647673
}));
@@ -667,7 +693,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
667693
};
668694
try {
669695
console.log(`Adding player ${player.playerid} to new tournament ${newTournamentid}`);
670-
await ddbDocClient.send(new PutCommand({
696+
await sendCommandWithRetry(new PutCommand({
671697
TableName: process.env.ABSTRACT_PLAY_TABLE,
672698
Item: playerdata
673699
}));
@@ -704,7 +730,7 @@ async function startTournament(users: UserLastSeen[], tournament: Tournament) {
704730
if (remove.length > 0) {
705731
for (const player of remove) {
706732
console.log(`Deleting tournament player record for ${player.playerid} from tournament ${tournament.id}`);
707-
await ddbDocClient.send(
733+
await sendCommandWithRetry(
708734
new DeleteCommand({
709735
TableName: process.env.ABSTRACT_PLAY_TABLE,
710736
Key: {
@@ -754,7 +780,7 @@ async function updateUserGames(userId: string, gamesUpdate: undefined | number,
754780
gameIDsChanged.length = 0;
755781
if (gamesUpdate === undefined) {
756782
// Update "old" users. This is a one-time update.
757-
return ddbDocClient.send(new UpdateCommand({
783+
return sendCommandWithRetry(new UpdateCommand({
758784
TableName: process.env.ABSTRACT_PLAY_TABLE,
759785
Key: { "pk": "USER", "sk": userId },
760786
ExpressionAttributeValues: { ":val": 1, ":gs": games },
@@ -763,7 +789,7 @@ async function updateUserGames(userId: string, gamesUpdate: undefined | number,
763789
} else {
764790
console.log(`updateUserGames: optimistically updating games for ${userId}`);
765791
try {
766-
await ddbDocClient.send(new UpdateCommand({
792+
await sendCommandWithRetry(new UpdateCommand({
767793
TableName: process.env.ABSTRACT_PLAY_TABLE,
768794
Key: { "pk": "USER", "sk": userId },
769795
ExpressionAttributeValues: { ":val": gamesUpdate, ":inc": 1, ":gs": games },
@@ -777,7 +803,7 @@ async function updateUserGames(userId: string, gamesUpdate: undefined | number,
777803
console.log(`updateUserGames: games has been modified by another process for ${userId}`);
778804
let count = 0;
779805
while (count < 3) {
780-
const userData = await ddbDocClient.send(
806+
const userData = await sendCommandWithRetry(
781807
new GetCommand({
782808
TableName: process.env.ABSTRACT_PLAY_TABLE,
783809
Key: {
@@ -801,7 +827,7 @@ async function updateUserGames(userId: string, gamesUpdate: undefined | number,
801827
}
802828
try {
803829
console.log(`updateUserGames: Update ${count} of games for user`, userId, newgames);
804-
await ddbDocClient.send(new UpdateCommand({
830+
await sendCommandWithRetry(new UpdateCommand({
805831
TableName: process.env.ABSTRACT_PLAY_TABLE,
806832
Key: { "pk": "USER", "sk": userId },
807833
ExpressionAttributeValues: { ":val": gamesUpdate, ":inc": 1, ":gs": newgames },
@@ -810,7 +836,11 @@ async function updateUserGames(userId: string, gamesUpdate: undefined | number,
810836
}));
811837
return;
812838
} catch (err: any) {
813-
count++;
839+
if (err.name === 'ConditionalCheckFailedException') {
840+
count++;
841+
} else {
842+
throw err;
843+
}
814844
}
815845
}
816846
new Error(`updateUserGames: Unable to update games for user ${userId} after 3 retries`);

0 commit comments

Comments
 (0)