@@ -62,6 +62,9 @@ export const compiledProcessDrain: unique symbol = Symbol.for("effect/Machine/co
6262/** @internal */
6363export const compiledProcessInitial : unique symbol = Symbol . for ( "effect/Machine/compiledProcessInitial" )
6464
65+ /** @internal */
66+ export const compiledProcessInitialSync : unique symbol = Symbol . for ( "effect/Machine/compiledProcessInitialSync" )
67+
6568/** @internal */
6669export const sendParentOverride : unique symbol = Symbol . for ( "effect/Machine/sendParentOverride" )
6770
@@ -363,6 +366,18 @@ export interface ProcessLogic<
363366 InitialError ,
364367 Requirements
365368 >
369+ /** @internal */
370+ readonly [ compiledProcessInitialSync ] ?: (
371+ scope : ProcessScope < Event >
372+ ) =>
373+ | { readonly state : State ; readonly done : false ; readonly output : undefined }
374+ | { readonly state : State ; readonly done : true ; readonly output : Output }
375+ | {
376+ readonly state : State
377+ readonly done : boolean
378+ readonly output : Output | undefined
379+ readonly executionState : unknown
380+ }
366381 run ( context : ProcessContext < State , Event > ) : Effect . Effect < Output , Error , Requirements >
367382 /** @internal */
368383 readonly drain ?: (
@@ -563,10 +578,13 @@ interface ChildRuntime {
563578}
564579
565580class OwnedChildRuntimeImpl implements OwnedChildRuntime {
581+ private scopedServices : Context . Context < any > | undefined
582+
566583 constructor (
567584 private readonly registry : ChildRegistry ,
568585 private readonly self : ProcessAddress < any > ,
569- private readonly runtime : ProcessRuntime
586+ private readonly runtime : ProcessRuntime ,
587+ private readonly services ?: Context . Context < any >
570588 ) { }
571589
572590 private has ( key : string ) : boolean {
@@ -596,15 +614,15 @@ class OwnedChildRuntimeImpl implements OwnedChildRuntime {
596614 if ( this . has ( options . key ) || this . registry . children . has ( options . id ) ) {
597615 return Effect . fail ( new ChildAlreadyExistsError ( { id : options . duplicateId } ) )
598616 }
599- this . registry . scope ??= Scope . makeUnsafe ( "parallel" )
617+ const scope = this . registry . scope ??= Scope . makeUnsafe ( "parallel" )
600618 this . registry . children . set ( options . id , {
601619 _tag : "Starting" ,
602620 token,
603621 ownerKey : options . key ,
604622 ownerPath : options . path ,
605623 ownerActive : true
606624 } )
607- return startLogicInternal ( logic , {
625+ const startOptions : StartInternalOptions = {
608626 detached : true ,
609627 id : options . id ,
610628 sendParent : ( event ) => options . sendParent ( isCurrent , event ) ,
@@ -620,15 +638,30 @@ class OwnedChildRuntimeImpl implements OwnedChildRuntime {
620638 skipStoppedOutcome : true ,
621639 parent : this . self ,
622640 runtime : this . runtime
623- } ) . pipe (
641+ }
642+ const synchronous = this . services !== undefined && options . onSnapshot === undefined &&
643+ logic [ childlessProcess ] === true && logic [ compiledProcessDrain ] !== undefined &&
644+ logic [ compiledProcessInitialSync ] !== undefined
645+ const start = synchronous
646+ ? Effect . flatMap (
647+ this . runtime . nextSessionId ,
648+ ( sessionId ) =>
649+ new CompiledProcess (
650+ logic ,
651+ startOptions ,
652+ this . scopedServices ??= Context . add ( this . services ! , Scope . Scope , scope ) ,
653+ sessionId
654+ ) . initializeOwnedSync ( )
655+ )
656+ : startLogicInternal ( logic , startOptions )
657+ const guarded = start . pipe (
624658 Effect . onExit ( ( exit ) => {
625659 if ( Exit . isSuccess ( exit ) ) return Effect . void
626660 unregisterChild ( this . registry , options . id , token )
627661 return startedChild === undefined ? Effect . void : startedChild . stop
628- } ) ,
629- Scope . provide ( this . registry . scope ) ,
630- Effect . asVoid
662+ } )
631663 )
664+ return ( synchronous ? guarded : Scope . provide ( guarded , scope ) ) . pipe ( Effect . asVoid )
632665 } )
633666 }
634667
@@ -682,7 +715,8 @@ const childlessRuntime: ChildRuntime = {
682715
683716const makeChildRuntime = (
684717 self : ProcessAddress < any > ,
685- runtime : ProcessRuntime
718+ runtime : ProcessRuntime ,
719+ services ?: Context . Context < any >
686720) : Effect . Effect < ChildRuntime > = >
687721 Effect . sync ( ( ) => {
688722 // Child-registry decisions are synchronous and every access below runs in
@@ -923,7 +957,7 @@ const makeChildRuntime = (
923957 changes,
924958 sendTo,
925959 stop,
926- owned : new OwnedChildRuntimeImpl ( registry , self , runtime )
960+ owned : new OwnedChildRuntimeImpl ( registry , self , runtime , services )
927961 }
928962 } )
929963
@@ -1407,6 +1441,13 @@ type CompiledTermination =
14071441 | { readonly _tag : "Done" ; readonly output : unknown }
14081442 | { readonly _tag : "Failure" ; readonly cause : Cause . Cause < unknown > }
14091443
1444+ type CompiledInitialized = {
1445+ readonly state : unknown
1446+ readonly done : boolean | undefined
1447+ readonly output : unknown
1448+ readonly executionState ?: unknown
1449+ }
1450+
14101451// Stopping is commonly used only for resource cleanup. Keep that path free of
14111452// Error stack capture and materialize the typed join failure only if observed.
14121453const CompiledStoppedCompletion : unique symbol = Symbol ( "effect/Machine/CompiledStoppedCompletion" )
@@ -1466,11 +1507,58 @@ class CompiledProcess implements MachineRef<any, any, any, any> {
14661507 }
14671508 }
14681509
1510+ initializeOwnedSync ( ) : Effect . Effect < MachineRef < any , any , any , any > , unknown > {
1511+ const parent = this . options . parent
1512+ const sendParent = this . options . sendParent ?? ( parent === undefined ? noParentSend : parent . send )
1513+ this . processScope = {
1514+ self : this . address ,
1515+ parent,
1516+ spawn : this . childRuntime . spawn ,
1517+ sendParent,
1518+ sendTo : this . childRuntime . sendTo ,
1519+ stopChild : this . childRuntime . stop ,
1520+ failCause : ( cause : Cause . Cause < unknown > ) => this . failCause ( cause )
1521+ }
1522+ const compiledInitial = this . logic [ compiledProcessInitialSync ] !
1523+ let initialized : CompiledInitialized
1524+ try {
1525+ initialized = compiledInitial ( this . processScope )
1526+ } catch ( error ) {
1527+ this . initializing = false
1528+ return Effect . fail ( error )
1529+ }
1530+ this . initializing = false
1531+ this . current = {
1532+ revision : 0 ,
1533+ terminalizing : false ,
1534+ changes : undefined ,
1535+ snapshot : { status : "active" , state : initialized . state }
1536+ }
1537+ this . compiledContext = new CompiledProcessContextImpl ( this . processScope , this . childRuntime . owned , this )
1538+ if ( "executionState" in initialized ) {
1539+ this . compiledContext . executionState = initialized . executionState
1540+ }
1541+ if ( this . options . onReadySync !== undefined && ! this . options . onReadySync ( this ) ) {
1542+ this . requestTerminationSync ( { _tag : "Stopped" } )
1543+ }
1544+ if ( initialized . done === true && this . requestedTermination === undefined ) {
1545+ this . requestTerminationSync ( { _tag : "Done" , output : initialized . output } )
1546+ }
1547+ if (
1548+ initialized . done === false && this . requestedTermination === undefined &&
1549+ this . mailbox . items === undefined
1550+ ) {
1551+ return Effect . succeed ( this )
1552+ }
1553+ this . draining = true
1554+ return Effect . provideContext ( this . drainRuntime ( ) , this . services ) . pipe ( Effect . as ( this ) )
1555+ }
1556+
14691557 initialize ( ) : Effect . Effect < MachineRef < any , any , any , any > , unknown , any > {
14701558 const self = this
14711559 return Effect . gen ( function * ( ) {
14721560 if ( self . logic [ childlessProcess ] !== true ) {
1473- self . childRuntime = yield * makeChildRuntime ( self . address , self . options . runtime )
1561+ self . childRuntime = yield * makeChildRuntime ( self . address , self . options . runtime , self . services )
14741562 }
14751563 const parent = self . options . parent
14761564 const sendParent = self . options . sendParent ?? ( parent === undefined ? noParentSend : parent . send )
@@ -1594,14 +1682,16 @@ class CompiledProcess implements MachineRef<any, any, any, any> {
15941682 }
15951683
15961684 private requestTermination ( requested : CompiledTermination ) : Effect . Effect < boolean> {
1597- return Effect . sync ( ( ) => {
1598- if ( this . requestedTermination !== undefined ) {
1599- return false
1600- }
1601- this . requestedTermination = requested
1602- this . reservedTerminationSnapshot = this . reserveTermination ( requested )
1603- return true
1604- } )
1685+ return Effect . sync ( ( ) => this . requestTerminationSync ( requested ) )
1686+ }
1687+
1688+ private requestTerminationSync ( requested : CompiledTermination ) : boolean {
1689+ if ( this . requestedTermination !== undefined ) {
1690+ return false
1691+ }
1692+ this . requestedTermination = requested
1693+ this . reservedTerminationSnapshot = this . reserveTermination ( requested )
1694+ return true
16051695 }
16061696
16071697 private reserveTermination (
0 commit comments