Add crash safety when accessing Google Sheet API by trying multiple times

This commit is contained in:
pikiou 2022-02-03 17:16:30 +01:00
parent 3264336aab
commit bd8a74cd17
3 changed files with 141 additions and 94 deletions

3
.gitignore vendored
View File

@ -14,6 +14,9 @@ public/*
# Access # Access
access/* access/*
# Gazettes
gazettes/*
# Misc # Misc
.DS_Store .DS_Store
*.log *.log

View File

@ -7,4 +7,6 @@ public/*
# Misc # Misc
*.log *.log
node_modules/*
access/*
gazettes/*

View File

@ -230,6 +230,7 @@ export class Sheet<
return return
} }
await tryNTimesVoidReturn(async () => {
// Load sheet into an array of objects // Load sheet into an array of objects
const rows = await sheet.getRows() const rows = await sheet.getRows()
await delayDBAccess() await delayDBAccess()
@ -289,6 +290,7 @@ export class Sheet<
await delayDBAccess() await delayDBAccess()
} }
} }
})
} }
private async dbLoadAsync(): Promise<void> { private async dbLoadAsync(): Promise<void> {
@ -299,6 +301,7 @@ export class Sheet<
return return
} }
await tryNTimesVoidReturn(async () => {
// Load sheet into an array of objects // Load sheet into an array of objects
const rows = (await sheet.getRows()) as StringifiedElement[] const rows = (await sheet.getRows()) as StringifiedElement[]
await delayDBAccess() await delayDBAccess()
@ -328,9 +331,12 @@ export class Sheet<
}) })
this._state = elements this._state = elements
})
} }
private async getGSheet(): Promise<GoogleSpreadsheetWorksheet | null> { private async getGSheet(): Promise<GoogleSpreadsheetWorksheet | null> {
return tryNTimes(
async () => {
if (creds === undefined) { if (creds === undefined) {
if (await hasGSheetsAccess()) { if (await hasGSheetsAccess()) {
const credsBuffer = await fs.readFile(CRED_PATH) const credsBuffer = await fs.readFile(CRED_PATH)
@ -347,6 +353,9 @@ export class Sheet<
await doc.useServiceAccountAuth(JSON.parse(creds)) await doc.useServiceAccountAuth(JSON.parse(creds))
await doc.loadInfo() await doc.loadInfo()
return doc.sheetsByTitle[this.sheetName] return doc.sheetsByTitle[this.sheetName]
},
() => null
)
} }
private parseElement( private parseElement(
@ -579,3 +588,36 @@ function parseDate(value: string): Date {
async function delayDBAccess(): Promise<void> { async function delayDBAccess(): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, DELAY_AFTER_QUERY)) return new Promise((resolve) => setTimeout(resolve, DELAY_AFTER_QUERY))
} }
async function tryNTimes<T>(
func: () => Promise<T> | T,
failFunc?: () => Promise<T> | T,
repeatCount = 5,
delayBetweenAttempts = 2000
): Promise<T> {
try {
return await func()
} catch (e: any) {
console.error(e?.error || e?.message || e)
console.error(`${repeatCount} attemps left every ${delayBetweenAttempts}`)
await new Promise<void>((resolve) => {
setTimeout(() => resolve(), delayBetweenAttempts)
})
if (repeatCount === 1) {
console.error(`No more attempts left every ${delayBetweenAttempts}`)
if (failFunc) {
return failFunc()
}
throw Error(e)
}
return tryNTimes(func, failFunc, repeatCount - 1, delayBetweenAttempts)
}
}
async function tryNTimesVoidReturn(
func: () => Promise<void> | void,
repeatCount = 5,
delayBetweenAttempts = 2000
): Promise<void> {
return tryNTimes(func, () => undefined, repeatCount, delayBetweenAttempts)
}