-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
onProgress() callback for BlockBlobClient.uploadData() in the browser isn't granular #32404
Comments
Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @xgithubtriage. |
related: #32247 |
@au5ton we do have some code for stream bodies specifically to enable progress with fetch:
I wonder if passing the progress callback as you suggest in
Perhaps there could be a separate callback to this operation (e.g. |
Thanks for clarifying this!
I'm not suggesting that the exported API surface of Currently, transfer progress is calculated over the entire file...
... and incremented and reported at the conclusion of each block. azure-sdk-for-js/sdk/storage/storage-blob/src/Clients.ts Lines 4289 to 4296 in 594557a
It could be possible that this is replaced so that each block is tracked separately and reported whenever Maybe something like this? If this approach is acceptable, I can make a PR. diff --git a/sdk/storage/storage-blob/src/Clients.ts b/sdk/storage/storage-blob/src/Clients.ts
index 7e5dcee0a7..e95d71185e 100644
--- a/sdk/storage/storage-blob/src/Clients.ts
+++ b/sdk/storage/storage-blob/src/Clients.ts
@@ -4270,28 +4270,45 @@ export class BlockBlobClient extends BlobClient {
const blockList: string[] = [];
const blockIDPrefix = randomUUID();
- let transferProgress: number = 0;
+ // Stores the amount of bytes progressed in each block
+ let transferProgressPerBlock: number[] = [];
const batch = new Batch(options.concurrency);
for (let i = 0; i < numBlocks; i++) {
+ // Initialize at 0
+ transferProgressPerBlock[i] = 0;
+ // Calculate block parameters
+ const start = blockSize * i;
+ const end = i === numBlocks - 1 ? size : start + blockSize;
+ const contentLength = end - start;
+ // Queue the block upload
batch.addOperation(async (): Promise<any> => {
const blockID = generateBlockID(blockIDPrefix, i);
- const start = blockSize * i;
- const end = i === numBlocks - 1 ? size : start + blockSize;
- const contentLength = end - start;
blockList.push(blockID);
await this.stageBlock(blockID, bodyFactory(start, contentLength), contentLength, {
abortSignal: options.abortSignal,
conditions: options.conditions,
encryptionScope: options.encryptionScope,
tracingOptions: updatedOptions.tracingOptions,
+ onProgress(progress) {
+ // Record the progress in this block by index. Will overwrite if block is retried.
+ transferProgressPerBlock[i] = progress.loadedBytes;
+ // Report progress externally
+ if (options.onProgress) {
+ options.onProgress!({
+ // Report the sum of the array
+ loadedBytes: transferProgressPerBlock.reduce((sum, a) => sum + a, 0),
+ });
+ }
+ },
});
// Update progress after block is successfully uploaded to server, in case of block trying
+ // In case of inconsistencies in `onProgress` report, write the final value ourselves
+ transferProgressPerBlock[i] = contentLength;
- // TODO: Hook with convenience layer progress event in finer level
- transferProgress += contentLength;
if (options.onProgress) {
options.onProgress!({
- loadedBytes: transferProgress,
+ // Report the sum of the array
+ loadedBytes: transferProgressPerBlock.reduce((sum, a) => sum + a, 0),
});
}
}); |
Describe the bug
The
onProgress()
callback when using BlockBlobClient.uploadData() in the browser is not granular and only updates after each block. This makes it impractical for progress bars and progress reporting without making chunks very small and inefficient.To Reproduce
Steps to reproduce the behavior:
onProgress
callback does not report the progress granularly in a useful way.Expected behavior
Expected that upload progress be recorded more interactively and at a sub-block refresh rate.
Screenshots
N/A
Additional context
From what I've researched, I am aware of a couple of different factors that contribute to this being the case:
@azure/core-rest-pipeline
:onProgress()
could be specified as an option after line 4287. (I don't mean hypothetically, I mean thatstageBlock()
implements it already)azure-sdk-for-js/sdk/storage/storage-blob/src/Clients.ts
Lines 4275 to 4299 in 594557a
BlockBlobClient.stageBlock(...)
the stack grows more complex and abstracted to fit the needs of a variety of environments and runtimes, but it would seem thatonProgress
it pretty respected for the most part underneath (from what I could tell at least).I (naively) think this could be mostly resolved with a few steps:
createXhrHttpClient()
in@azure/core-rest-pipeline
to allow browser consumers to import it again. Maybe there's a history with this being deprecated/removed?BlockBlobClient.uploadSeekableInternal()
and as a result inBlockBlobClient.uploadData()
(see snippets to stub code above)What is the team's stance on this? Thanks.
The text was updated successfully, but these errors were encountered: