-
Notifications
You must be signed in to change notification settings - Fork 6
piece-retriever: add try different SP on retrieval failure #438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7e4e82e
d7437fc
07105aa
9332577
75ba68c
7dc2cd7
05dedf7
0f96737
c2e1d34
518df70
77a47d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ import { | |
| measureStreamedEgress, | ||
| } from '../lib/retrieval.js' | ||
| import { | ||
| getStorageProviderAndValidatePayer, | ||
| getRetrievalCandidatesAndValidatePayer, | ||
| logRetrievalResult, | ||
| updateDataSetStats, | ||
| } from '../lib/store.js' | ||
|
|
@@ -71,18 +71,17 @@ export default { | |
| // Timestamp to measure file retrieval performance (from cache and from SP) | ||
| const fetchStartedAt = performance.now() | ||
|
|
||
| const [{ serviceProviderId, serviceUrl, dataSetId }, isBadBit] = | ||
| await Promise.all([ | ||
| getStorageProviderAndValidatePayer( | ||
| env, | ||
| payerWalletAddress, | ||
| pieceCid, | ||
| env.ENFORCE_EGRESS_QUOTA, | ||
| ), | ||
| env.BAD_BITS_KV.get(`bad-bits:${await getBadBitsEntry(pieceCid)}`, { | ||
| type: 'json', | ||
| }), | ||
| ]) | ||
| const [retrievalCandidates, isBadBit] = await Promise.all([ | ||
| getRetrievalCandidatesAndValidatePayer( | ||
| env, | ||
| payerWalletAddress, | ||
| pieceCid, | ||
| env.ENFORCE_EGRESS_QUOTA, | ||
| ), | ||
| env.BAD_BITS_KV.get(`bad-bits:${await getBadBitsEntry(pieceCid)}`, { | ||
| type: 'json', | ||
| }), | ||
| ]) | ||
|
|
||
| httpAssert( | ||
| !isBadBit, | ||
|
|
@@ -91,23 +90,55 @@ export default { | |
| ) | ||
|
|
||
| httpAssert( | ||
| serviceProviderId, | ||
| 404, | ||
| `Unsupported Service Provider: ${serviceProviderId}`, | ||
| retrievalCandidates.length > 0, | ||
| 500, | ||
| 'Service provider lookup failed', | ||
| ) | ||
|
|
||
| let retrievalCandidate | ||
| let retrievalResult | ||
| const retrievalAttempts = [] | ||
|
|
||
| try { | ||
| retrievalResult = await retrieveFile( | ||
| ctx, | ||
| serviceUrl, | ||
| pieceCid, | ||
| request, | ||
| env.ORIGIN_CACHE_TTL, | ||
| { signal: request.signal }, | ||
| while (retrievalCandidates.length > 0) { | ||
| const retrievalCandidateIndex = Math.floor( | ||
| Math.random() * retrievalCandidates.length, | ||
| ) | ||
| } catch {} | ||
| retrievalCandidate = retrievalCandidates[retrievalCandidateIndex] | ||
| retrievalAttempts.push(retrievalCandidate) | ||
| retrievalCandidates.splice(retrievalCandidateIndex, 1) | ||
| console.log('Attempting retrieval', retrievalCandidate) | ||
| try { | ||
| retrievalResult = await retrieveFile( | ||
| ctx, | ||
| retrievalCandidate.serviceUrl, | ||
| pieceCid, | ||
| request, | ||
| env.ORIGIN_CACHE_TTL, | ||
| { signal: request.signal }, | ||
| ) | ||
| if (retrievalResult.response.ok) { | ||
| break | ||
| } | ||
| console.log( | ||
| `Retrieval attempt failed: HTTP ${retrievalResult.response.status}`, | ||
| { | ||
| retrievalCandidate, | ||
| willRetry: retrievalCandidates.length > 0, | ||
| }, | ||
| ) | ||
| } catch (err) { | ||
| const msg = | ||
| typeof err === 'object' && err !== null && 'message' in err | ||
| ? err.message | ||
| : String(err) | ||
| console.log(`Retrieval attempt failed: ${msg}`, { | ||
| retrievalCandidate, | ||
| willRetry: retrievalCandidates.length > 0, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| httpAssert(retrievalCandidate, 500, 'should never happen') | ||
|
|
||
| if (!retrievalResult || retrievalResult.response.status >= 500) { | ||
| ctx.waitUntil( | ||
|
|
@@ -117,16 +148,18 @@ export default { | |
| egressBytes: 0, | ||
| requestCountryCode, | ||
| timestamp: requestTimestamp, | ||
| dataSetId, | ||
| dataSetId: retrievalCandidate.dataSetId, | ||
| botName, | ||
| }), | ||
| ) | ||
| const response = new Response( | ||
| `Service provider ${serviceProviderId} is unavailable${retrievalResult ? ` at ${retrievalResult.url}` : ''}`, | ||
| `No available service provider found. Attempted: ${retrievalAttempts.map((a) => `ID=${a.serviceProviderId} (Service URL=${a.serviceUrl})`).join(', ')}`, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will eventually need to update filbeam-bot to support an array of IDs in this header: https://github.com/filbeam/bot/blob/c4479005a7834e0e708d1dc910bc9fd4baf5794a/index.js#L197-L203 Maybe after we land my PR filbeam/bot#40 first, to avoid merge conflicts.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| { | ||
| status: 502, | ||
| headers: new Headers({ | ||
| 'X-Data-Set-ID': dataSetId, | ||
| 'X-Data-Set-ID': retrievalAttempts | ||
| .map((a) => a.dataSetId) | ||
| .join(','), | ||
| }), | ||
| }, | ||
| ) | ||
|
|
@@ -145,7 +178,7 @@ export default { | |
| egressBytes: 0, | ||
| requestCountryCode, | ||
| timestamp: requestTimestamp, | ||
| dataSetId, | ||
| dataSetId: retrievalCandidate.dataSetId, | ||
| botName, | ||
| }), | ||
| ) | ||
|
|
@@ -154,7 +187,7 @@ export default { | |
| retrievalResult.response, | ||
| ) | ||
| setContentSecurityPolicy(response) | ||
| response.headers.set('X-Data-Set-ID', dataSetId) | ||
| response.headers.set('X-Data-Set-ID', retrievalCandidate.dataSetId) | ||
| response.headers.set( | ||
| 'Cache-Control', | ||
| `public, max-age=${env.CLIENT_CACHE_TTL}`, | ||
|
|
@@ -185,12 +218,12 @@ export default { | |
| fetchTtlb: lastByteFetchedAt - fetchStartedAt, | ||
| workerTtfb: firstByteAt - workerStartedAt, | ||
| }, | ||
| dataSetId, | ||
| dataSetId: retrievalCandidate.dataSetId, | ||
| botName, | ||
| }) | ||
|
|
||
| await updateDataSetStats(env, { | ||
| dataSetId, | ||
| dataSetId: retrievalCandidate.dataSetId, | ||
| egressBytes, | ||
| cacheMiss: retrievalResult.cacheMiss, | ||
| enforceEgressQuota: env.ENFORCE_EGRESS_QUOTA, | ||
|
|
@@ -205,7 +238,7 @@ export default { | |
| headers: retrievalResult.response.headers, | ||
| }) | ||
| setContentSecurityPolicy(response) | ||
| response.headers.set('X-Data-Set-ID', dataSetId) | ||
| response.headers.set('X-Data-Set-ID', retrievalCandidate.dataSetId) | ||
| response.headers.set( | ||
| 'Cache-Control', | ||
| `public, max-age=${env.CLIENT_CACHE_TTL}`, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.