@@ -469,56 +469,43 @@ const makeChildRuntime = (
469469 }
470470 }
471471
472- const close = < A , E > ( _exit : Exit . Exit < A , E > ) : Effect . Effect < void > =>
473- Effect . sync ( ( ) => {
472+ const close = < A , E > ( exit : Exit . Exit < A , E > ) : Effect . Effect < void > =>
473+ Effect . suspend ( ( ) => {
474474 if ( registry . closed ) {
475- return undefined
475+ return Effect . void
476476 }
477477 registry . closed = true
478478 if ( registry . scope === undefined ) {
479- return undefined
479+ return Effect . void
480480 }
481- const children = Array . from ( registry . children . values ( ) ) . flatMap ( ( entry ) =>
482- entry . _tag === "Started" ? [ entry . ref ] : [ ]
483- )
484- return { children, scope : registry . scope }
485- } ) . pipe (
486- Effect . flatMap ( ( resources ) =>
487- resources === undefined
488- ? Effect . void
489- : Effect . all (
490- [
491- ...resources . children . map ( ( child ) => child . stop ) ,
492- ...( resources . scope === undefined ? [ ] : [ Scope . close ( resources . scope , _exit ) ] )
493- ] ,
494- { concurrency : "unbounded" , discard : true }
495- )
496- )
497- )
498-
499- const getOrCreateScope : Effect . Effect < Scope . Closeable | undefined > = Effect . sync ( ( ) => {
500- if ( registry . closed ) {
501- return undefined
502- }
503- if ( registry . scope === undefined ) {
504- registry . scope = Scope . makeUnsafe ( "parallel" )
505- }
506- return registry . scope
507- } )
508-
509- const reserve = (
510- key : ChildKey ,
511- token : symbol
512- ) : Effect . Effect < boolean , ChildAlreadyExistsError > =>
513- Effect . suspend ( ( ) => {
514- if ( registry . closed ) {
515- return Effect . succeed ( false )
481+ const finalizers = Scope . closeUnsafe ( registry . scope , exit )
482+ let first : Effect . Effect < void > | undefined
483+ let rest : Array < Effect . Effect < void > > | undefined
484+ for ( const entry of registry . children . values ( ) ) {
485+ if ( entry . _tag !== "Started" ) {
486+ continue
487+ }
488+ if ( first === undefined ) {
489+ first = entry . ref . stop
490+ } else {
491+ rest ??= [ first ]
492+ rest . push ( entry . ref . stop )
493+ }
516494 }
517- if ( typeof key === "string" && registry . children . has ( key ) ) {
518- return Effect . fail ( new ChildAlreadyExistsError ( { id : key } ) )
495+ if ( finalizers !== undefined ) {
496+ if ( first === undefined ) {
497+ first = finalizers
498+ } else {
499+ rest ??= [ first ]
500+ rest . push ( finalizers )
501+ }
519502 }
520- registry . children . set ( key , { _tag : "Starting" , token } )
521- return Effect . succeed ( true )
503+ const cleanup = rest ?? first
504+ return cleanup === undefined
505+ ? Effect . void
506+ : Array . isArray ( cleanup )
507+ ? Effect . all ( cleanup , { concurrency : "unbounded" , discard : true } )
508+ : cleanup
522509 } )
523510
524511 const unregister = (
@@ -681,47 +668,50 @@ const makeChildRuntime = (
681668 const token = Symbol ( )
682669 const key = spawnOptions ?. id ?? token
683670 let startedChild : MachineRef < any , any , any , any > | undefined
684- return getOrCreateScope . pipe (
685- Effect . flatMap ( ( childScope ) =>
686- childScope === undefined
687- ? Effect . interrupt
688- : Effect . gen ( function * ( ) {
689- const reserved = yield * reserve ( key , token )
690- if ( ! reserved ) {
691- return yield * Effect . interrupt
692- }
693- return yield * startLogicInternal ( logic , {
694- detached : true ,
695- ...( spawnOptions ?. id === undefined ? undefined : { id : spawnOptions . id } ) ,
696- ...( spawnOptions ?. onOutcome === undefined ? undefined : { onOutcome : spawnOptions . onOutcome } ) ,
697- ...( spawnOptions ?. [ activeSnapshotObserver ] === undefined
698- ? undefined
699- : { onSnapshot : spawnOptions [ activeSnapshotObserver ] } ) ,
700- ...( spawnOptions ?. [ sendParentOverride ] === undefined
701- ? undefined
702- : { sendParent : spawnOptions [ sendParentOverride ] } ) ,
703- onReady : ( child , requestChildStop ) =>
704- Effect . sync ( ( ) => {
705- startedChild = child
706- } ) . pipe (
707- Effect . andThen ( register ( key , token , child , spawnOptions ?. descriptor ) ) ,
708- Effect . flatMap ( ( registered ) => registered ? Effect . void : requestChildStop )
709- ) ,
710- onStop : unregister ( key , token ) ,
711- parent : self ,
712- runtime
713- } ) . pipe (
714- Effect . onExit ( ( exit ) =>
715- Exit . isFailure ( exit )
716- ? unregister ( key , token ) . pipe (
717- Effect . andThen ( startedChild === undefined ? Effect . void : startedChild . stop )
718- )
719- : Effect . void
720- )
671+ return Effect . suspend ( ( ) : Effect . Effect <
672+ MachineRef < ChildState , ChildEvent , ChildError , ChildOutput > ,
673+ ChildAlreadyExistsError | ChildInitialError ,
674+ Exclude < ChildRequirements , Scope . Scope >
675+ > => {
676+ if ( registry . closed ) {
677+ return Effect . interrupt
678+ }
679+ if ( typeof key === "string" && registry . children . has ( key ) ) {
680+ return Effect . fail ( new ChildAlreadyExistsError ( { id : key } ) )
681+ }
682+ registry . scope ??= Scope . makeUnsafe ( "parallel" )
683+ registry . children . set ( key , { _tag : "Starting" , token } )
684+ return startLogicInternal ( logic , {
685+ detached : true ,
686+ ...( spawnOptions ?. id === undefined ? undefined : { id : spawnOptions . id } ) ,
687+ ...( spawnOptions ?. onOutcome === undefined ? undefined : { onOutcome : spawnOptions . onOutcome } ) ,
688+ ...( spawnOptions ?. [ activeSnapshotObserver ] === undefined
689+ ? undefined
690+ : { onSnapshot : spawnOptions [ activeSnapshotObserver ] } ) ,
691+ ...( spawnOptions ?. [ sendParentOverride ] === undefined
692+ ? undefined
693+ : { sendParent : spawnOptions [ sendParentOverride ] } ) ,
694+ onReady : ( child , requestChildStop ) =>
695+ Effect . sync ( ( ) => {
696+ startedChild = child
697+ } ) . pipe (
698+ Effect . andThen ( register ( key , token , child , spawnOptions ?. descriptor ) ) ,
699+ Effect . flatMap ( ( registered ) => registered ? Effect . void : requestChildStop )
700+ ) ,
701+ onStop : unregister ( key , token ) ,
702+ parent : self ,
703+ runtime
704+ } ) . pipe (
705+ Effect . onExit ( ( exit ) =>
706+ Exit . isFailure ( exit )
707+ ? unregister ( key , token ) . pipe (
708+ Effect . andThen ( startedChild === undefined ? Effect . void : startedChild . stop )
721709 )
722- } ) . pipe ( Scope . provide ( childScope ) )
710+ : Effect . void
711+ ) ,
712+ Scope . provide ( registry . scope )
723713 )
724- ) as Effect . Effect <
714+ } ) as Effect . Effect <
725715 MachineRef < ChildState , ChildEvent , ChildError , ChildOutput > ,
726716 ChildAlreadyExistsError | ChildInitialError ,
727717 Exclude < ChildRequirements , Scope . Scope >
0 commit comments