Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
[C-2872] Fix image retries (#3773)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers authored Jul 20, 2023
1 parent b99b93a commit b63107b
Showing 1 changed file with 54 additions and 40 deletions.
94 changes: 54 additions & 40 deletions packages/common/src/services/audius-backend/AudiusBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ export const audiusBackend = ({
}
}

async function preloadImage(url: string) {
async function preloadImage(url: string): Promise<boolean> {
if (!preloadImageTimer) {
const batchSize =
getRemoteVar(IntKeys.IMAGE_QUICK_FETCH_PERFORMANCE_BATCH_SIZE) ??
Expand All @@ -387,35 +387,50 @@ export const audiusBackend = ({
}
)
}
const start = preloadImageTimer.start()
const timeoutMs =
getRemoteVar(IntKeys.IMAGE_QUICK_FETCH_TIMEOUT_MS) ?? undefined
let timeoutId: Nullable<NodeJS.Timeout> = null

return new Promise<string | false>((resolve) => {
const start = preloadImageTimer.start()
try {
const response = await Promise.race([
fetch(url),
new Promise<Response>((_resolve, reject) => {
timeoutId = setTimeout(() => reject(new Error('Timeout')), timeoutMs)
})
])

if (timeoutId) {
clearTimeout(timeoutId)
}

const timeoutMs =
getRemoteVar(IntKeys.IMAGE_QUICK_FETCH_TIMEOUT_MS) ?? undefined
const timeout = setTimeout(() => {
preloadImageTimer.end(start)
resolve(false)
}, timeoutMs)
if (!response.ok) {
return false
}

// Avoid garbage collection by keeping a few images in an in-mem array
const blob = await response.blob()
const objectUrl = URL.createObjectURL(blob)
const image = new Image()
avoidGC.push(image)
if (avoidGC.length > IMAGE_CACHE_MAX_SIZE) avoidGC.shift()

image.onload = () => {
preloadImageTimer.end(start)
clearTimeout(timeout)
resolve(url)
}
await new Promise<void>((resolve, reject) => {
image.onload = () => {
preloadImageTimer.end(start)
resolve()
}
image.onerror = () => {
preloadImageTimer.end(start)
reject(new Error('Image loading error'))
}
image.src = objectUrl
})

image.onerror = () => {
preloadImageTimer.end(start)
clearTimeout(timeout)
resolve(false)
}
image.src = url
})
return true
} catch (error) {
preloadImageTimer.end(start)
return false
}
}

async function fetchCID(cid: CID, cache = true, asUrl = true) {
Expand Down Expand Up @@ -452,26 +467,25 @@ export const audiusBackend = ({
}

const storageNodeSelector = await getStorageNodeSelector()
const storageNode = storageNodeSelector.getNodes(cid)[0]
const imageUrl = `${storageNode}/content/${cidFileName}`

if (imagePreloader) {
try {
const preloaded = await imagePreloader(imageUrl)
if (preloaded) {
const storageNodes = storageNodeSelector.getNodes(cid)
for (const storageNode of storageNodes) {
const imageUrl = `${storageNode}/content/${cidFileName}`

if (imagePreloader) {
try {
const preloaded = await imagePreloader(imageUrl)
if (preloaded) {
return imageUrl
}
} catch (e) {
// swallow error and continue
}
} else {
const isSuccessful = await preloadImage(imageUrl)
if (isSuccessful) {
CIDCache.add(cidFileName, imageUrl)
return imageUrl
}
} catch (e) {
// swallow error and continue
}
} else {
// Attempt to fetch/load the image using the first creator node gateway
const preloadedImageUrl = await preloadImage(imageUrl)

// If the image is loaded, add to cache and return
if (preloadedImageUrl) {
CIDCache.add(cidFileName, preloadedImageUrl)
return preloadedImageUrl
}
}
return ''
Expand Down

0 comments on commit b63107b

Please sign in to comment.