@@ -519,17 +519,20 @@ export const createExecutor = <
519519 return yield * provider . get ( id ) ;
520520 }
521521
522- // Fallback: ask enumerating providers in registration order.
523- // First non-null wins. Providers that throw are treated as
524- // "don't have it" and skipped so one flaky provider doesn 't
522+ // Fallback: ask every enumerating provider in parallel. First
523+ // non-null in registration order wins. Providers that throw
524+ // are treated as "don't have it" so one flaky provider can 't
525525 // block resolution via others.
526- for ( const provider of secretProviders . values ( ) ) {
527- if ( ! provider . list ) continue ;
528- const value = yield * provider
529- . get ( id )
530- . pipe ( Effect . catchAll ( ( ) => Effect . succeed ( null ) ) ) ;
531- if ( value !== null ) return value ;
532- }
526+ const candidates = [ ...secretProviders . values ( ) ] . filter (
527+ ( p ) => p . list ,
528+ ) ;
529+ const values = yield * Effect . all (
530+ candidates . map ( ( p ) =>
531+ p . get ( id ) . pipe ( Effect . catchAll ( ( ) => Effect . succeed ( null ) ) ) ,
532+ ) ,
533+ { concurrency : "unbounded" } ,
534+ ) ;
535+ for ( const value of values ) if ( value !== null ) return value ;
533536 return null ;
534537 } ) ;
535538
@@ -595,11 +598,17 @@ export const createExecutor = <
595598
596599 const secretsRemove = ( id : string ) : Effect . Effect < void , Error > =>
597600 Effect . gen ( function * ( ) {
598- for ( const provider of secretProviders . values ( ) ) {
599- if ( provider . writable && provider . delete ) {
600- yield * provider . delete ( id ) ;
601- }
602- }
601+ // Providers don't coordinate on which of them own the id — they
602+ // each get asked. Most calls are no-ops; fan them out so one
603+ // slow provider doesn't serialize the rest.
604+ const deleters = [ ...secretProviders . values ( ) ] . filter (
605+ ( p ) : p is typeof p & { delete : NonNullable < typeof p . delete > } =>
606+ ! ! ( p . writable && p . delete ) ,
607+ ) ;
608+ yield * Effect . all (
609+ deleters . map ( ( p ) => p . delete ( id ) ) ,
610+ { concurrency : "unbounded" } ,
611+ ) ;
603612 yield * core . delete ( {
604613 model : "secret" ,
605614 where : [ { field : "id" , value : id } ] ,
@@ -643,15 +652,26 @@ export const createExecutor = <
643652 ) ;
644653 }
645654
646- // Then every provider that can enumerate itself. If a provider
647- // fails to list (unlocked vault, network error), swallow the
648- // failure and continue — one flaky provider shouldn't block
649- // the whole list.
650- for ( const [ providerKey , provider ] of secretProviders . entries ( ) ) {
651- if ( ! provider . list ) continue ;
652- const entries = yield * provider
653- . list ( )
654- . pipe ( Effect . catchAll ( ( ) => Effect . succeed ( [ ] as const ) ) ) ;
655+ // Then every provider that can enumerate itself, in parallel.
656+ // If a provider fails to list (unlocked vault, network error),
657+ // swallow the failure so one flaky provider can't block the
658+ // whole list. Merge in registration order afterwards so the
659+ // "first provider wins" precedence stays deterministic.
660+ const listers = [ ...secretProviders . entries ( ) ] . filter (
661+ ( [ , p ] ) => p . list ,
662+ ) ;
663+ const lists = yield * Effect . all (
664+ listers . map ( ( [ key , p ] ) =>
665+ p
666+ . list ! ( )
667+ . pipe (
668+ Effect . catchAll ( ( ) => Effect . succeed ( [ ] as const ) ) ,
669+ Effect . map ( ( entries ) => ( { key, entries } ) ) ,
670+ ) ,
671+ ) ,
672+ { concurrency : "unbounded" } ,
673+ ) ;
674+ for ( const { key, entries } of lists ) {
655675 for ( const entry of entries ) {
656676 if ( byId . has ( entry . id ) ) continue ; // core row wins
657677 byId . set (
@@ -660,7 +680,7 @@ export const createExecutor = <
660680 id : SecretId . make ( entry . id ) ,
661681 scopeId : scope . id ,
662682 name : entry . name ,
663- provider : providerKey ,
683+ provider : key ,
664684 createdAt : new Date ( ) ,
665685 } ) ,
666686 ) ;
0 commit comments