Skip to content

Commit 640b529

Browse files
feat: delete Blobs stores in batches (#532)
1 parent c7ccca0 commit 640b529

File tree

4 files changed

+48
-12
lines changed

4 files changed

+48
-12
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export interface DeleteStoreResponse {
22
blobs_deleted: number
3+
has_more: boolean
34
}

packages/blobs/src/main.test.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,7 +1500,7 @@ describe('deleteAll', () => {
15001500
const mockStore = new MockFetch()
15011501
.delete({
15021502
headers: { authorization: `Bearer ${apiToken}` },
1503-
response: Response.json({ blobs_deleted: 3 }),
1503+
response: Response.json({ blobs_deleted: 3, has_more: false }),
15041504
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production`,
15051505
})
15061506
.inject()
@@ -1542,7 +1542,7 @@ describe('deleteAll', () => {
15421542
const mockStore = new MockFetch()
15431543
.delete({
15441544
headers: { authorization: `Bearer ${apiToken}` },
1545-
response: Response.json({ blobs_deleted: 3 }),
1545+
response: Response.json({ blobs_deleted: 3, has_more: false }),
15461546
url: `https://api.netlify.com/api/v1/blobs/${siteID}/oldie`,
15471547
})
15481548
.inject()
@@ -1565,7 +1565,7 @@ describe('deleteAll', () => {
15651565
const mockStore = new MockFetch()
15661566
.delete({
15671567
headers: { authorization: `Bearer ${edgeToken}` },
1568-
response: Response.json({ blobs_deleted: 3 }),
1568+
response: Response.json({ blobs_deleted: 3, has_more: false }),
15691569
url: `${edgeURL}/${siteID}/site:production`,
15701570
})
15711571
.inject()
@@ -1605,6 +1605,33 @@ describe('deleteAll', () => {
16051605

16061606
expect(mockStore.fulfilled).toBeTruthy()
16071607
})
1608+
1609+
test('Handles paginated deletion with multiple batches', async () => {
1610+
const mockStore = new MockFetch()
1611+
.delete({
1612+
headers: { authorization: `Bearer ${edgeToken}` },
1613+
response: Response.json({ blobs_deleted: 100, has_more: true }),
1614+
url: `${edgeURL}/${siteID}/site:production`,
1615+
})
1616+
.delete({
1617+
headers: { authorization: `Bearer ${edgeToken}` },
1618+
response: Response.json({ blobs_deleted: 50, has_more: false }),
1619+
url: `${edgeURL}/${siteID}/site:production`,
1620+
})
1621+
.inject()
1622+
1623+
const blobs = getStore({
1624+
edgeURL,
1625+
name: 'production',
1626+
token: edgeToken,
1627+
siteID,
1628+
})
1629+
1630+
const res = await blobs.deleteAll()
1631+
1632+
expect(mockStore.fulfilled).toBeTruthy()
1633+
expect(res.deletedBlobs).toBe(150)
1634+
})
16081635
})
16091636
})
16101637

packages/blobs/src/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export class BlobsServer {
180180
}
181181
}
182182

183-
return Response.json({ blobs_deleted: blobsDeleted })
183+
return Response.json({ blobs_deleted: blobsDeleted, has_more: false })
184184
}
185185

186186
private async get(req: Request): Promise<Response> {

packages/blobs/src/store.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,20 +152,28 @@ export class Store {
152152
}
153153

154154
async deleteAll(): Promise<DeleteStoreResult> {
155-
const res = await this.client.makeRequest({ method: HTTPMethod.DELETE, storeName: this.name })
155+
let totalDeletedBlobs = 0
156+
let hasMore = true
156157

157-
if (res.status !== 200) {
158-
throw new BlobsInternalError(res)
159-
}
158+
while (hasMore) {
159+
const res = await this.client.makeRequest({ method: HTTPMethod.DELETE, storeName: this.name })
160+
161+
if (res.status !== 200) {
162+
throw new BlobsInternalError(res)
163+
}
160164

161-
const data = (await res.json()) as DeleteStoreResponse
165+
const data = (await res.json()) as DeleteStoreResponse
162166

163-
if (typeof data.blobs_deleted !== 'number') {
164-
throw new BlobsInternalError(res)
167+
if (typeof data.blobs_deleted !== 'number') {
168+
throw new BlobsInternalError(res)
169+
}
170+
171+
totalDeletedBlobs += data.blobs_deleted
172+
hasMore = typeof data.has_more === 'boolean' && data.has_more
165173
}
166174

167175
return {
168-
deletedBlobs: data.blobs_deleted,
176+
deletedBlobs: totalDeletedBlobs,
169177
}
170178
}
171179

0 commit comments

Comments
 (0)