2
2
* @since 1.0.0
3
3
*/
4
4
import * as Rpc from "@effect/rpc/Rpc"
5
+ import { DurableDeferred } from "@effect/workflow"
5
6
import * as Activity from "@effect/workflow/Activity"
6
7
import * as DurableClock from "@effect/workflow/DurableClock"
7
8
import * as Workflow from "@effect/workflow/Workflow"
@@ -23,9 +24,7 @@ import * as Entity from "./Entity.js"
23
24
import { EntityAddress } from "./EntityAddress.js"
24
25
import { EntityId } from "./EntityId.js"
25
26
import { EntityType } from "./EntityType.js"
26
- import * as Message from "./Message.js"
27
27
import { MessageStorage } from "./MessageStorage.js"
28
- import * as Reply from "./Reply.js"
29
28
import type { WithExitEncoded } from "./Reply.js"
30
29
import * as Sharding from "./Sharding.js"
31
30
import * as Snowflake from "./Snowflake.js"
@@ -37,7 +36,6 @@ import * as Snowflake from "./Snowflake.js"
37
36
export const make = Effect . gen ( function * ( ) {
38
37
const sharding = yield * Sharding . Sharding
39
38
const storage = yield * MessageStorage
40
- const snowflakeGen = yield * Snowflake . Generator
41
39
42
40
const entities = new Map <
43
41
string ,
@@ -129,9 +127,24 @@ export const make = Effect.gen(function*() {
129
127
Effect . orDie
130
128
)
131
129
130
+ const clearClock = Effect . fnUntraced ( function * ( options : {
131
+ readonly executionId : string
132
+ } ) {
133
+ const entityId = EntityId . make ( options . executionId )
134
+ const shardId = sharding . getShardId ( entityId )
135
+ const clockAddress = new EntityAddress ( {
136
+ entityType : ClockEntity . type ,
137
+ entityId,
138
+ shardId
139
+ } )
140
+ yield * storage . clearAddress ( clockAddress )
141
+ } )
142
+
132
143
return WorkflowEngine . of ( {
133
- register : ( workflow , execute ) =>
134
- Effect . suspend ( ( ) => {
144
+ register ( workflow , execute ) {
145
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
146
+ const engine = this
147
+ return Effect . suspend ( ( ) => {
135
148
if ( entities . has ( workflow . name ) ) {
136
149
return Effect . dieMessage ( `Workflow ${ workflow . name } already registered` )
137
150
}
@@ -143,19 +156,36 @@ export const make = Effect.gen(function*() {
143
156
const address = yield * Entity . CurrentAddress
144
157
const executionId = address . entityId
145
158
return {
146
- run : ( request : Entity . Request < any > ) =>
147
- execute ( request . payload , executionId ) . pipe (
159
+ run : ( request : Entity . Request < any > ) => {
160
+ const instance = WorkflowInstance . of ( {
161
+ workflow,
162
+ executionId,
163
+ suspended : false
164
+ } )
165
+ return execute ( request . payload , executionId ) . pipe (
166
+ Effect . onExit ( ( ) => {
167
+ if ( ! instance . suspended ) {
168
+ return Effect . void
169
+ }
170
+ return engine . deferredResult ( InterruptSignal ) . pipe (
171
+ Effect . flatMap ( ( maybeResult ) => {
172
+ if ( Option . isNone ( maybeResult ) ) {
173
+ return Effect . void
174
+ }
175
+ instance . suspended = false
176
+ return Effect . zipRight (
177
+ Effect . ignore ( clearClock ( { executionId } ) ) ,
178
+ Effect . interrupt
179
+ )
180
+ } ) ,
181
+ Effect . orDie
182
+ )
183
+ } ) ,
148
184
Effect . scoped ,
149
185
Workflow . intoResult ,
150
- Effect . provideService (
151
- WorkflowInstance ,
152
- WorkflowInstance . of ( {
153
- workflow,
154
- executionId,
155
- suspended : false
156
- } )
157
- )
158
- ) as any ,
186
+ Effect . provideService ( WorkflowInstance , instance )
187
+ ) as any
188
+ } ,
159
189
activity : Effect . fnUntraced ( function * ( request : Entity . Request < any > ) {
160
190
const activityId = `${ executionId } /${ request . payload . name } `
161
191
let entry = activities . get ( activityId )
@@ -186,7 +216,8 @@ export const make = Effect.gen(function*() {
186
216
}
187
217
} )
188
218
) as Effect . Effect < void >
189
- } ) ,
219
+ } )
220
+ } ,
190
221
191
222
execute : ( { discard, executionId, payload, workflow } ) =>
192
223
RcMap . get ( clients , workflow . name ) . pipe (
@@ -196,7 +227,7 @@ export const make = Effect.gen(function*() {
196
227
) ,
197
228
198
229
interrupt : Effect . fnUntraced (
199
- function * ( workflow , executionId ) {
230
+ function * ( this : WorkflowEngine [ "Type" ] , workflow , executionId ) {
200
231
const requestId = yield * requestIdFor ( {
201
232
entityType : `Workflow/${ workflow . name } ` ,
202
233
executionId,
@@ -214,41 +245,12 @@ export const make = Effect.gen(function*() {
214
245
return
215
246
}
216
247
217
- const entityId = EntityId . make ( executionId )
218
- const shardId = sharding . getShardId ( entityId )
219
- const workflowAddress = new EntityAddress ( {
220
- entityType : EntityType . make ( `Workflow/${ workflow . name } ` ) ,
221
- entityId,
222
- shardId
223
- } )
224
- const deferredAddress = new EntityAddress ( {
225
- entityType : DeferredEntity . type ,
226
- entityId,
227
- shardId
228
- } )
229
- const clockAddress = new EntityAddress ( {
230
- entityType : ClockEntity . type ,
231
- entityId,
232
- shardId
248
+ yield * this . deferredDone ( {
249
+ workflowName : workflow . name ,
250
+ executionId,
251
+ deferred : InterruptSignal ,
252
+ exit : { _tag : "Success" , value : void 0 }
233
253
} )
234
- if ( Option . isNone ( reply ) ) {
235
- yield * sharding . sendOutgoing (
236
- Message . OutgoingEnvelope . interrupt ( {
237
- address : workflowAddress ,
238
- id : snowflakeGen . unsafeNext ( ) ,
239
- requestId : requestId . value
240
- } ) ,
241
- true
242
- )
243
- } else {
244
- yield * sharding . reset ( requestId . value )
245
- }
246
- yield * storage . saveReply ( Reply . ReplyWithContext . interrupt ( {
247
- id : snowflakeGen . unsafeNext ( ) ,
248
- requestId : requestId . value
249
- } ) )
250
- yield * storage . clearAddress ( deferredAddress )
251
- yield * storage . clearAddress ( clockAddress )
252
254
} ,
253
255
Effect . retry ( {
254
256
while : ( e ) => e . _tag === "PersistenceError" ,
@@ -461,6 +463,8 @@ const ClockEntityLayer = ClockEntity.toLayer(Effect.gen(function*() {
461
463
}
462
464
} ) )
463
465
466
+ const InterruptSignal = DurableDeferred . make ( "Workflow/InterruptSignal" )
467
+
464
468
/**
465
469
* @since 1.0.0
466
470
* @category Layers
@@ -471,6 +475,5 @@ export const layer: Layer.Layer<
471
475
Sharding . Sharding | MessageStorage
472
476
> = DeferredEntityLayer . pipe (
473
477
Layer . merge ( ClockEntityLayer ) ,
474
- Layer . provideMerge ( Layer . scoped ( WorkflowEngine , make ) ) ,
475
- Layer . provide ( Snowflake . layerGenerator )
478
+ Layer . provideMerge ( Layer . scoped ( WorkflowEngine , make ) )
476
479
)
0 commit comments