feat: add retry on file upload failure when offline #44
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I Right that when I have no internet the method completes 10 mins after start with default configuration?
In addition I would make the max attempt count a config in the storage client as well so you don't have to specify it always.
Yup, that is correct. It might be a problem for some applications that are already using the library huh? I will update the default max attempts to 1. Also, yeah let me update the code so that the user can just define the maxAttempts value when initializing the client so that they don't have to update it every single time. Do you think we should leave the option to override it in each individual functions though? |
Yeah I think setting the default to 1 is better. Also, is there any way to stop the retrying? For example if the user wants to abort the upload? |
Aborting the upload is a great point. I wonder how we can do it elegantly. |
I think we can't abort the actual request. dart-lang/http#424 So we can only abort the retrying. I don't know if this is how one would do it in Dart as well, but we could inspire from postgrest-js https://supabase.com/docs/reference/javascript/db-abortsignal |
@Vinzent03 final abortController = StorageAbortController();
await client.from('public').upload(
path,
file,
abortController: abortController,
);
...
// Some where else:
abortController.abort(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Do we want to additionally cancel the future as stated here?
How can we integrate the max attempts field with supabase-dart
or supbase-flutter
? Do we want to put that in each constructor? Another approach is to add a method to change the config. This would allow changing the count after object initialization as well.
Co-authored-by: Bruno D'Luka <45696119+bdlukaa@users.noreply.github.com>
Thanks for the suggestion! Let me add it!
I want to say just put it in each constructors would be good enough, but would you think creating a separate configuration method might provide better developer experience? |
I definitely think so. One issue with cancelling the future could be though that, as far as understand this, the actual request is no cancelled so that the file may still get uploaded after abort. This should not be the case, so the abort should just stop the retrying. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely think so.
Let's do this!
One issue with cancelling the future could be though that, as far as understand this, the actual request is no cancelled so that the file may still get uploaded after abort. This should not be the case, so the abort should just stop the retrying.
With the current state, there will not be any more retry attempts once the user calls abortController.abort()
. I tried to include CancelableOperation
in the code, but I feel like it might not solve any issues on top of what is already implemented, so I ended up just leaving the code as is, but what do you think?
Yeah I changed my mind and I think just aborting the retry is better than ignoring the result of the future. The dev can still do the same on the end result future. But we need to document that, because even after abort the request could go on for a long time until it finishes or fails. Maybe |
Agree. Let's rename it. What do you think about the following rename? final retryController = StorageRetryController();
await client.from('public').upload(
path,
file,
retryController: retryController,
);
...
// Some where else:
retryController.cancel(); |
That's great. Let's use these names. |
Looks great, but what about the config method to change the retry attempts count? |
@Vinzent03 |
Good question, I can't think of one currently. I just like offering the dev all freedom, when it's not complicated to implement it. I'm fine with leaving as it is as well. |
@Vinzent03 |
I agree. Let's merge. |
What kind of change does this PR introduce?
Uploading large files on a spotty connection could be tough.
Resumable uploads is not yet supported on Supabase, but we can easily implement retries. This PR adds a retry logic to file uploads in a exponentially backing off manner like the following:
By default, the max attempts is set to 25, which should be roughly 10 minutes. 10 minutes was the default time set for Firebase storage. Users can change the retry count like the following. Not sure if this API would provide the best developer experience, so would love to hear comments/ suggestions about anything regarding this PR!
What is the current behavior?
If a file upload fails, it does no retry, which makes is hard to upload large files over a spotty network connection.
What is the new behavior?
File upload is automatically retried on SocketException or TimeoutException.
Additional context
This feature is not supported on JS client, but there was an feedback from customers handling large files. After some internal discussions, we thought it would make make sense to add this feature to the Flutter SDK.