Skip to content
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

Add onShouldRetry as option to @uppy/tus #3720

Merged
merged 18 commits into from
May 17, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e/clients/dashboard-tus/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '@uppy/dashboard/dist/style.css'
const companionUrl = 'http://localhost:3020'
const uppy = new Uppy()
.use(Dashboard, { target: '#app', inline: true })
.use(Tus, { endpoint: 'https://tusd.tusdemo.net/files' })
.use(Tus, { endpoint: 'https://tusd.tusdemo.net/files', retryStatusCodes: [429, 401] })
Murderlon marked this conversation as resolved.
Show resolved Hide resolved
.use(Url, { target: Dashboard, companionUrl })
.use(Unsplash, { target: Dashboard, companionUrl })

Expand Down
27 changes: 2 additions & 25 deletions e2e/cypress/integration/dashboard-tus.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,6 @@ describe('Dashboard with Tus', () => {
cy.intercept('http://localhost:3020/search/unsplash/*').as('unsplash')
})

it('should emit `error` and `upload-error` events on failed POST request', () => {
cy.get('@file-input').attachFile(['images/traffic.jpg'])

const error = cy.spy()
const uploadError = cy.spy()
cy.window().then(({ uppy }) => {
uppy.on('upload-error', uploadError)
uppy.on('error', error)
})

cy.get('.uppy-StatusBar-actionBtn--upload').click()

cy.intercept(
{ method: 'POST', url: 'https://tusd.tusdemo.net/*', times: 1 },
{ statusCode: 401, body: { code: 401, message: 'Expired JWT Token' } },
).as('post')

cy.wait('@post').then(() => {
expect(error).to.be.called
expect(uploadError).to.be.called
})
})

it('should upload cat image successfully', () => {
cy.get('@file-input').attachFile('images/cat.jpg')
cy.get('.uppy-StatusBar-actionBtn--upload').click()
Expand All @@ -48,7 +25,7 @@ describe('Dashboard with Tus', () => {
cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete')
})

it('should start exponential backoff when receiving HTTP 429', () => {
it('should start exponential backoff on HTTP 429 from `retryStatusCodes`', () => {
cy.get('@file-input').attachFile(['images/baboon.png'])
cy.get('.uppy-StatusBar-actionBtn--upload').click()

Expand All @@ -68,7 +45,7 @@ describe('Dashboard with Tus', () => {

it('should upload remote image with URL plugin', () => {
cy.get('[data-cy="Url"]').click()
cy.get('.uppy-Url-input').type('https://via.placeholder.com/600x400')
cy.get('.uppy-Url-input').type('https://github.com/transloadit/uppy/raw/main/e2e/cypress/fixtures/images/cat.jpg')
cy.get('.uppy-Url-importButton').click()
cy.get('.uppy-StatusBar-actionBtn--upload').click()
cy.wait('@url')
Expand Down
4 changes: 3 additions & 1 deletion packages/@uppy/tus/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ module.exports = class Tus extends BasePlugin {
useFastRemoteRetry: true,
limit: 20,
retryDelays: tusDefaultOptions.retryDelays,
retryStatusCodes: [429],
withCredentials: false,
}

Expand Down Expand Up @@ -278,7 +279,8 @@ module.exports = class Tus extends BasePlugin {

uploadOptions.onShouldRetry = (err) => {
const status = err?.originalResponse?.getStatus()
if (status === 429) {

if (this.opts.retryStatusCodes.includes(status)) {
// HTTP 429 Too Many Requests => to avoid the whole download to fail, pause all requests.
if (!this.requests.isPaused) {
const next = this.#retryDelayIterator?.next()
Expand Down
1 change: 1 addition & 0 deletions packages/@uppy/tus/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface TusOptions extends PluginOptions, TusUploadOptions {
limit?: number
useFastRemoteRetry?: boolean
withCredentials?: boolean
retryStatusCodes: Array<number>
}

declare class Tus extends BasePlugin<TusOptions> {}
Expand Down
4 changes: 4 additions & 0 deletions website/src/docs/tus.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ When uploading a chunk fails, automatically try again after the millisecond inte

Set to `null` to disable automatic retries, and fail instantly if any chunk fails to upload.

### `retryStatusCodes: [429]`

Tus can retry with [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) when receiving 429 (Too Many Requests), or other configured status codes. This can be useful to retry when you hit an API rate limit or when your authentication token is expired.

### `metaFields: null`

Pass an array of field names to limit the metadata fields that will be added to uploads as [Tus Metadata](https://tus.io/protocols/resumable-upload.html#upload-metadata).
Expand Down