Skip to content

Commit d4e0598

Browse files
R2-3560: document listParts and listMultipartUploads on the Workers binding
1 parent 08cce1d commit d4e0598

File tree

2 files changed

+180
-1
lines changed

2 files changed

+180
-1
lines changed

src/content/docs/r2/api/workers/workers-api-reference.mdx

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ export default {
104104
- Returns an object representing a multipart upload with the given key and uploadId.
105105
- The resumeMultipartUpload operation does not perform any checks to ensure the validity of the uploadId, nor does it verify the existence of a corresponding active multipart upload. This is done to minimize latency before being able to call subsequent operations on the `R2MultipartUpload` object.
106106

107+
- `listMultipartUploads` <Type text="(options?: R2ListMultipartUploadsOptions): Promise<R2MultipartUploads>" />
108+
109+
- Returns an `R2MultipartUploads` containing a list of in-progress multipart uploads in the bucket.
110+
- The returned list of multipart uploads is ordered lexicographically by key.
111+
- Refer to [R2ListMultipartUploadsOptions](#r2listmultipartuploadsoptions) for available options.
112+
107113
## `R2Object` definition
108114

109115
`R2Object` is created when you `PUT` an object into an R2 bucket. `R2Object` represents the metadata of an object based on the information provided by the uploader. Every object that you `PUT` into an R2 bucket will have an `R2Object` created.
@@ -229,6 +235,12 @@ A multipart upload can be completed or aborted at any time, either through the S
229235
- Completes the multipart upload with the given parts.
230236
- Returns a Promise that resolves when the complete operation has finished. Once this happens, the object is immediately accessible globally by any subsequent read operation.
231237

238+
- `listParts` <Type text="(options?: R2ListPartsOptions): Promise<R2UploadedParts>" />
239+
240+
- Returns an `R2UploadedParts` containing a list of parts that have been uploaded to this multipart upload.
241+
- Parts are returned in ascending order by part number.
242+
- Refer to [R2ListPartsOptions](#r2listpartsoptions) for available options.
243+
232244
## Method-specific types
233245

234246
### R2GetOptions
@@ -416,6 +428,114 @@ An object containing an `R2Object` array, returned by `BUCKET_BINDING.list()`.
416428

417429
- For example, if no prefix is provided and the delimiter is '/', `foo/bar/baz` would return `foo` as a delimited prefix. If `foo/` was passed as a prefix with the same structure and delimiter, `foo/bar` would be returned as a delimited prefix.
418430

431+
### R2ListMultipartUploadsOptions
432+
433+
- `limit` <Type text="number" /> <MetaInfo text="optional" />
434+
435+
- The number of results to return. Defaults to `1000`, with a maximum of `1000`.
436+
437+
- `prefix` <Type text="string" /> <MetaInfo text="optional" />
438+
439+
- The prefix to match keys against. Keys will only be returned if they start with given prefix.
440+
441+
- `cursor` <Type text="string" /> <MetaInfo text="optional" />
442+
443+
- An opaque token that indicates where to continue listing multipart uploads from. A cursor can be retrieved from a previous list operation.
444+
445+
- `delimiter` <Type text="string" /> <MetaInfo text="optional" />
446+
447+
- The character to use when grouping keys.
448+
449+
- `startAfter` <Type text="string" /> <MetaInfo text="optional" />
450+
451+
- A key to start listing multipart uploads after. Used for pagination in combination with cursor.
452+
453+
### R2MultipartUploads
454+
455+
An object containing an array of `R2MultipartUploadListing` objects, returned by `BUCKET_BINDING.listMultipartUploads()`.
456+
457+
- `uploads` <Type text="Array<R2MultipartUploadListing>" />
458+
459+
- An array of multipart uploads matching the `listMultipartUploads` request.
460+
461+
- `truncated` <Type text="boolean" />
462+
463+
- If true, indicates there are more results to be retrieved for the current `listMultipartUploads` request.
464+
465+
- `cursor` <Type text="string" /> <MetaInfo text="optional" />
466+
467+
- A token that can be passed to future `listMultipartUploads` calls to resume listing from that point. Only present if truncated is true.
468+
469+
- `delimitedPrefixes` <Type text="Array<string>" />
470+
471+
- If a delimiter has been specified, contains all prefixes between the specified prefix and the next occurrence of the delimiter.
472+
473+
### R2MultipartUploadListing
474+
475+
An object representing a single multipart upload in the list returned by `listMultipartUploads`.
476+
477+
- `key` <Type text="string" />
478+
479+
- The key (object name) for this multipart upload.
480+
481+
- `uploadId` <Type text="string" />
482+
483+
- The unique identifier for this multipart upload.
484+
485+
- `initiated` <Type text="Date" /> <MetaInfo text="optional" />
486+
487+
- A Date object representing when the multipart upload was initiated.
488+
489+
- `storageClass` <Type text="string" /> <MetaInfo text="optional" />
490+
491+
- The storage class associated with this multipart upload.
492+
493+
### R2ListPartsOptions
494+
495+
- `maxParts` <Type text="number" /> <MetaInfo text="optional" />
496+
497+
- The maximum number of parts to return. Defaults to `1000`, with a maximum of `1000`.
498+
499+
- `partNumberMarker` <Type text="number" /> <MetaInfo text="optional" />
500+
501+
- The part number to start listing from. Parts with a part number greater than this value will be returned. Must be a positive integer.
502+
503+
### R2UploadedParts
504+
505+
An object containing an array of uploaded parts, returned by `multipartUpload.listParts()`.
506+
507+
- `parts` <Type text="Array<R2UploadedPartInfo>" />
508+
509+
- An array of parts that have been uploaded to this multipart upload.
510+
511+
- `truncated` <Type text="boolean" />
512+
513+
- If true, indicates there are more parts to be retrieved for the current `listParts` request.
514+
515+
- `partNumberMarker` <Type text="number" /> <MetaInfo text="optional" />
516+
517+
- A part number marker that can be passed to future `listParts` calls to resume listing from that point. Only present if truncated is true.
518+
519+
### R2UploadedPartInfo
520+
521+
An object representing detailed information about an uploaded part.
522+
523+
- `partNumber` <Type text="number" />
524+
525+
- The part number of this part.
526+
527+
- `etag` <Type text="string" />
528+
529+
- The etag of this part.
530+
531+
- `size` <Type text="number" />
532+
533+
- The size of this part in bytes.
534+
535+
- `uploaded` <Type text="Date" />
536+
537+
- A Date object representing when this part was uploaded.
538+
419539
### Conditional operations
420540

421541
You can pass an `R2Conditional` object to `R2GetOptions` and `R2PutOptions`. If the condition check for `get()` fails, the body will not be returned. This will make `get()` have lower latency.

src/content/docs/r2/api/workers/workers-multipart-usage.mdx

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,65 @@ def upload_part(filename, partsize, url, uploadId, index):
266266
upload_file(worker_endpoint, filename, partsize)
267267
```
268268

269+
## List multipart uploads
270+
271+
You can list all in-progress multipart uploads in a bucket using the `listMultipartUploads` method. This is useful for managing and cleaning up incomplete uploads.
272+
273+
```js
274+
// List all in-progress multipart uploads
275+
const uploads = await env.MY_BUCKET.listMultipartUploads();
276+
277+
for (const upload of uploads.uploads) {
278+
console.log(`Upload: ${upload.key}, ID: ${upload.uploadId}, Started: ${upload.initiated}`);
279+
}
280+
281+
// Handle pagination for large results
282+
let cursor = uploads.cursor;
283+
while (uploads.truncated) {
284+
const moreUploads = await env.MY_BUCKET.listMultipartUploads({ cursor });
285+
for (const upload of moreUploads.uploads) {
286+
console.log(`Upload: ${upload.key}, ID: ${upload.uploadId}`);
287+
}
288+
cursor = moreUploads.cursor;
289+
uploads.truncated = moreUploads.truncated;
290+
}
291+
292+
// Filter by prefix
293+
const filteredUploads = await env.MY_BUCKET.listMultipartUploads({
294+
prefix: "uploads/",
295+
delimiter: "/",
296+
});
297+
```
298+
299+
## List parts of a multipart upload
300+
301+
You can list all parts that have been uploaded to a multipart upload using the `listParts` method. This is useful for resuming uploads or verifying which parts have been uploaded.
302+
303+
```js
304+
// Resume an existing multipart upload
305+
const multipartUpload = env.MY_BUCKET.resumeMultipartUpload(key, uploadId);
306+
307+
// List all uploaded parts
308+
const result = await multipartUpload.listParts();
309+
310+
for (const part of result.parts) {
311+
console.log(
312+
`Part ${part.partNumber}: etag=${part.etag}, size=${part.size}, uploaded=${part.uploaded}`
313+
);
314+
}
315+
316+
// Handle pagination for uploads with many parts
317+
let partNumberMarker = result.partNumberMarker;
318+
while (result.truncated) {
319+
const moreParts = await multipartUpload.listParts({ partNumberMarker });
320+
for (const part of moreParts.parts) {
321+
console.log(`Part ${part.partNumber}: size=${part.size}`);
322+
}
323+
partNumberMarker = moreParts.partNumberMarker;
324+
result.truncated = moreParts.truncated;
325+
}
326+
```
327+
269328
## State management
270329

271330
The stateful nature of multipart uploads does not easily map to the usage model of Workers, which are inherently stateless. In a normal multipart upload, the multipart upload is usually performed in one continuous execution of the client application. This is different from multipart uploads in a Worker, which will often be completed over multiple invocations of that Worker. This makes state management more challenging.
@@ -274,4 +333,4 @@ To overcome this, the state associated with a multipart upload, namely the `uplo
274333

275334
In the example Worker and Python application described in this guide, the state of the multipart upload is tracked in the client application which sends requests to the Worker, with the necessary state contained in each request. Keeping track of the multipart state in the client application enables maximal flexibility and allows for parallel and unordered uploads of each part.
276335

277-
When keeping track of this state in the client is impossible, alternative designs can be considered. For example, you could track the `uploadId` and which parts have been uploaded in a Durable Object or other database.
336+
When keeping track of this state in the client is impossible, alternative designs can be considered. For example, you could track the `uploadId` and which parts have been uploaded in a Durable Object or other database. Alternatively, use `listMultipartUploads` and `listParts` to query the current state of uploads directly from R2.

0 commit comments

Comments
 (0)