11import type { H3Event } from "h3" ;
22
33export default eventHandler ( async ( event ) => {
4- setResponseHeader ( event , "Cache-Control" , "no-cache" ) ;
5- setResponseHeader ( event , "Content-Type" , "application/json" ) ;
6-
74 const rmStaleKeyHeader = getHeader ( event , "sb-rm-stale-key" ) ;
85 const signal = toWebRequest ( event ) . signal ;
96 const { rmStaleKey } = useRuntimeConfig ( event ) ;
@@ -18,40 +15,65 @@ export default eventHandler(async (event) => {
1815
1916 const result = await iterateAndDelete ( event , signal , {
2017 prefix : bucket === 'packages' ? usePackagesBucket . base : useTemplatesBucket . base ,
21- limit : 100 ,
18+ limit : 1000 ,
2219 cursor : cursor || undefined ,
2320 } , remove ) ;
2421
22+ setResponseHeader ( event , "Content-Type" , "application/json" ) ;
23+
2524 return {
2625 result,
2726 } ;
2827} ) ;
2928
29+ // Helper for concurrency limiting
30+ async function mapWithConcurrency < T , R > ( items : T [ ] , concurrency : number , fn : ( item : T ) => Promise < R > ) : Promise < R [ ] > {
31+ const results : R [ ] = [ ] ;
32+ let i = 0 ;
33+ const executing : Promise < void > [ ] = [ ] ;
34+
35+ async function enqueue ( item : T ) {
36+ const result = await fn ( item ) ;
37+ results . push ( result ) ;
38+ }
39+
40+ while ( i < items . length ) {
41+ const item = items [ i ++ ] ;
42+ const p = enqueue ( item ) ;
43+ executing . push ( p . then ( ( ) => {
44+ executing . splice ( executing . indexOf ( p ) , 1 ) ;
45+ } ) ) ;
46+ if ( executing . length >= concurrency ) {
47+ await Promise . race ( executing ) ;
48+ }
49+ }
50+ await Promise . all ( executing ) ;
51+ return results ;
52+ }
53+
3054async function iterateAndDelete ( event : H3Event , signal : AbortSignal , opts : R2ListOptions , remove : boolean ) {
3155 const binding = useBinding ( event ) ;
3256 let truncated = true ;
33- let cursor : string | undefined ;
57+ let cursor : string | undefined = opts . cursor ;
58+ let processed = 0 ;
3459 const removedItems : Array < { key : string ; uploaded : Date ; downloadedAt ?: Date } > = [ ] ;
3560 const downloadedAtBucket = useDownloadedAtBucket ( event ) ;
3661 const today = Date . parse ( new Date ( ) . toString ( ) ) ;
62+ const CONCURRENCY = 10 ;
3763
3864 while ( truncated && ! signal . aborted ) {
39- if ( removedItems . length >= 1000 ) {
40- break
65+ if ( removedItems . length >= 100 || processed >= 10000 ) {
66+ break ;
4167 }
4268 const next = await binding . list ( {
4369 ...opts ,
4470 cursor,
4571 } ) ;
46- for ( const object of next . objects ) {
47- if ( signal . aborted ) {
48- break ;
49- }
72+ processed += next . objects . length ;
73+
74+ await mapWithConcurrency ( next . objects , CONCURRENCY , async ( object ) => {
75+ if ( signal . aborted ) return ;
5076 const uploaded = Date . parse ( object . uploaded . toString ( ) ) ;
51- // removedItems.push({
52- // key: object.key,
53- // uploaded: new Date(object.uploaded),
54- // });
5577 const uploadedDate = new Date ( uploaded ) ;
5678 const sixMonthsAgo = new Date ( today ) ;
5779 sixMonthsAgo . setMonth ( sixMonthsAgo . getMonth ( ) - 6 ) ;
@@ -64,12 +86,11 @@ async function iterateAndDelete(event: H3Event, signal: AbortSignal, opts: R2Lis
6486 await binding . delete ( object . key ) ;
6587 await downloadedAtBucket . removeItem ( object . key ) ;
6688 }
67- continue ;
89+ return ;
6890 }
6991 const downloadedAt = await downloadedAtBucket . getItem ( object . key ) ;
70-
7192 if ( ! downloadedAt ) {
72- continue ;
93+ return ;
7394 }
7495 const downloadedAtDate = new Date ( downloadedAt ) ;
7596 const oneMonthAgo = new Date ( today ) ;
@@ -88,9 +109,9 @@ async function iterateAndDelete(event: H3Event, signal: AbortSignal, opts: R2Lis
88109 await binding . delete ( object . key ) ;
89110 await downloadedAtBucket . removeItem ( object . key ) ;
90111 }
91-
92112 }
93- }
113+ } ) ;
114+
94115 truncated = next . truncated ;
95116 if ( next . truncated ) {
96117 cursor = next . cursor ;
@@ -103,3 +124,4 @@ async function iterateAndDelete(event: H3Event, signal: AbortSignal, opts: R2Lis
103124 } ;
104125}
105126
127+
0 commit comments