Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7677256

Browse files
Merge pull request#1432 from square/sedwards/add-dropped-actions-tracking
Add `onSessionCancelled` API
2 parents922e4fe +d78e5af commit7677256

File tree

13 files changed

+432
-21
lines changed

13 files changed

+432
-21
lines changed

‎workflow-runtime/api/workflow-runtime.api‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public final class com/squareup/workflow1/NoopWorkflowInterceptor : com/squareup
55
public fun onRender (Ljava/lang/Object;Ljava/lang/Object;Lcom/squareup/workflow1/BaseRenderContext;Lkotlin/jvm/functions/Function3;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Ljava/lang/Object;
66
public fun onRenderAndSnapshot (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/RenderingAndSnapshot;
77
public fun onRuntimeUpdate (Lcom/squareup/workflow1/WorkflowInterceptor$RuntimeUpdate;)V
8+
public fun onSessionCancelled (Ljava/util/concurrent/CancellationException;Ljava/util/List;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)V
89
public fun onSessionStarted (Lkotlinx/coroutines/CoroutineScope;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)V
910
public fun onSnapshotState (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/Snapshot;
1011
public fun onSnapshotStateWithChildren (Lkotlin/jvm/functions/Function0;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/TreeSnapshot;
@@ -34,6 +35,7 @@ public class com/squareup/workflow1/SimpleLoggingWorkflowInterceptor : com/squar
3435
public fun onRender (Ljava/lang/Object;Ljava/lang/Object;Lcom/squareup/workflow1/BaseRenderContext;Lkotlin/jvm/functions/Function3;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Ljava/lang/Object;
3536
public fun onRenderAndSnapshot (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/RenderingAndSnapshot;
3637
public fun onRuntimeUpdate (Lcom/squareup/workflow1/WorkflowInterceptor$RuntimeUpdate;)V
38+
public fun onSessionCancelled (Ljava/util/concurrent/CancellationException;Ljava/util/List;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)V
3739
public fun onSessionStarted (Lkotlinx/coroutines/CoroutineScope;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)V
3840
public fun onSnapshotState (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/Snapshot;
3941
public fun onSnapshotStateWithChildren (Lkotlin/jvm/functions/Function0;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/TreeSnapshot;
@@ -58,6 +60,7 @@ public abstract interface class com/squareup/workflow1/WorkflowInterceptor {
5860
public abstract fun onRender (Ljava/lang/Object;Ljava/lang/Object;Lcom/squareup/workflow1/BaseRenderContext;Lkotlin/jvm/functions/Function3;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Ljava/lang/Object;
5961
public abstract fun onRenderAndSnapshot (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/RenderingAndSnapshot;
6062
public abstract fun onRuntimeUpdate (Lcom/squareup/workflow1/WorkflowInterceptor$RuntimeUpdate;)V
63+
public abstract fun onSessionCancelled (Ljava/util/concurrent/CancellationException;Ljava/util/List;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)V
6164
public abstract fun onSessionStarted (Lkotlinx/coroutines/CoroutineScope;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)V
6265
public abstract fun onSnapshotState (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/Snapshot;
6366
public abstract fun onSnapshotStateWithChildren (Lkotlin/jvm/functions/Function0;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/TreeSnapshot;
@@ -69,6 +72,7 @@ public final class com/squareup/workflow1/WorkflowInterceptor$DefaultImpls {
6972
public static fun onRender (Lcom/squareup/workflow1/WorkflowInterceptor;Ljava/lang/Object;Ljava/lang/Object;Lcom/squareup/workflow1/BaseRenderContext;Lkotlin/jvm/functions/Function3;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Ljava/lang/Object;
7073
public static fun onRenderAndSnapshot (Lcom/squareup/workflow1/WorkflowInterceptor;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/RenderingAndSnapshot;
7174
public static fun onRuntimeUpdate (Lcom/squareup/workflow1/WorkflowInterceptor;Lcom/squareup/workflow1/WorkflowInterceptor$RuntimeUpdate;)V
75+
public static fun onSessionCancelled (Lcom/squareup/workflow1/WorkflowInterceptor;Ljava/util/concurrent/CancellationException;Ljava/util/List;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)V
7276
public static fun onSessionStarted (Lcom/squareup/workflow1/WorkflowInterceptor;Lkotlinx/coroutines/CoroutineScope;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)V
7377
public static fun onSnapshotState (Lcom/squareup/workflow1/WorkflowInterceptor;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/Snapshot;
7478
public static fun onSnapshotStateWithChildren (Lcom/squareup/workflow1/WorkflowInterceptor;Lkotlin/jvm/functions/Function0;Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Lcom/squareup/workflow1/TreeSnapshot;

‎workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/SimpleLoggingWorkflowInterceptor.kt‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package com.squareup.workflow1
22

33
importcom.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor
44
importcom.squareup.workflow1.WorkflowInterceptor.WorkflowSession
5+
importkotlinx.coroutines.CancellationException
56
importkotlinx.coroutines.CoroutineScope
6-
importkotlinx.coroutines.Job
77

88
/**
99
* A [WorkflowInterceptor] that just prints all method calls using [log].
@@ -14,9 +14,14 @@ public open class SimpleLoggingWorkflowInterceptor : WorkflowInterceptor {
1414
session:WorkflowSession
1515
) {
1616
invokeSafely("logBeforeMethod") { logBeforeMethod("onInstanceStarted", session) }
17-
workflowScope.coroutineContext[Job]!!.invokeOnCompletion {
18-
invokeSafely("logAfterMethod") { logAfterMethod("onInstanceStarted", session) }
19-
}
17+
}
18+
19+
overridefun <P,S,O>onSessionCancelled(
20+
cause:CancellationException?,
21+
droppedActions:List<WorkflowAction<P,S,O>>,
22+
session:WorkflowSession
23+
) {
24+
invokeSafely("logAfterMethod") { logAfterMethod("onInstanceStarted", session) }
2025
}
2126

2227
overridefun <P,S>onInitialState(

‎workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.squareup.workflow1
22

33
importcom.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor
44
importcom.squareup.workflow1.WorkflowInterceptor.WorkflowSession
5+
importkotlinx.coroutines.CancellationException
56
importkotlinx.coroutines.CoroutineScope
67
importkotlinx.coroutines.Job
78
importkotlin.coroutines.CoroutineContext
@@ -75,6 +76,19 @@ public interface WorkflowInterceptor {
7576
session:WorkflowSession
7677
):Unit=Unit
7778

79+
/**
80+
* Called when the session is ending, when the Workflow's [CoroutineScope] is being cancelled.
81+
*
82+
* @param cause The cause of the cancellation if non-null.
83+
* @param droppedActions Any actions that were queued in this node's channel at the time of
84+
* cancellation.
85+
*/
86+
publicfun <P,S,O>onSessionCancelled(
87+
cause:CancellationException?,
88+
droppedActions:List<WorkflowAction<P,S,O>>,
89+
session:WorkflowSession
90+
):Unit=Unit
91+
7892
/**
7993
* Intercepts calls to [StatefulWorkflow.initialState].
8094
*/

‎workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/ChainedWorkflowInterceptor.kt‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.squareup.workflow1.WorkflowInterceptor
1111
importcom.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor
1212
importcom.squareup.workflow1.WorkflowInterceptor.RuntimeUpdate
1313
importcom.squareup.workflow1.WorkflowInterceptor.WorkflowSession
14+
importkotlinx.coroutines.CancellationException
1415
importkotlinx.coroutines.CoroutineScope
1516
importkotlin.reflect.KType
1617

@@ -32,6 +33,20 @@ internal class ChainedWorkflowInterceptor(
3233
interceptors.forEach { it.onSessionStarted(workflowScope, session) }
3334
}
3435

36+
overridefun <P,S,O>onSessionCancelled(
37+
cause:CancellationException?,
38+
droppedActions:List<WorkflowAction<P,S,O>>,
39+
session:WorkflowSession
40+
) {
41+
interceptors.forEach {
42+
it.onSessionCancelled(
43+
cause= cause,
44+
droppedActions= droppedActions,
45+
session= session
46+
)
47+
}
48+
}
49+
3550
overridefun <P,S>onInitialState(
3651
props:P,
3752
snapshot:Snapshot?,

‎workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowNode.kt‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,10 +265,22 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
265265
/**
266266
* Cancels this state machine host, and any coroutines started as children of it.
267267
*
268-
* This must be called when the caller will no longer call [registerTreeActionSelectors]. It is an error to call [registerTreeActionSelectors]
269-
* after calling this method.
268+
* This must be called when the caller will no longer call [registerTreeActionSelectors].
269+
*It is an error to call [registerTreeActionSelectors]after calling this method.
270270
*/
271271
funcancel(cause:CancellationException? = null) {
272+
val hangingActions= mutableListOf<WorkflowAction<PropsT,StateT,OutputT>>()
273+
// This will only be non-null if there is an action buffered and ready.
274+
var nextAction= eventActionsChannel.tryReceive().getOrNull()
275+
while (nextAction!=null) {
276+
hangingActions.add(nextAction)
277+
nextAction= eventActionsChannel.tryReceive().getOrNull()
278+
}
279+
interceptor.onSessionCancelled(
280+
cause= cause,
281+
droppedActions= hangingActions,
282+
session=this
283+
)
272284
coroutineContext.cancel(cause)
273285
lastRendering=NullableInitBox()
274286
}

‎workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/SimpleLoggingWorkflowInterceptorTest.kt‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,21 @@ internal class SimpleLoggingWorkflowInterceptorTest {
1919
interceptor.onSessionStarted(scope,TestWorkflowSession)
2020
scope.cancel()
2121

22-
assertEquals(ErrorLoggingInterceptor.EXPECTED_ERRORS, interceptor.errors)
22+
// Only the first, since we don't get cancellation directly from the scope cancellation.
23+
// For that we use onSessionCancelled()
24+
assertEquals(listOf(ErrorLoggingInterceptor.EXPECTED_ERRORS.first()), interceptor.errors)
25+
}
26+
27+
@TestfunonSessionCancelled_handles_logging_exceptions() {
28+
val interceptor=ErrorLoggingInterceptor()
29+
interceptor.onSessionCancelled<Unit,Unit,Nothing>(
30+
cause=null,
31+
droppedActions= emptyList(),
32+
session=TestWorkflowSession
33+
)
34+
35+
// Only the second error, since onSessionCancelled only calls logAfterMethod
36+
assertEquals(listOf(ErrorLoggingInterceptor.EXPECTED_ERRORS.last()), interceptor.errors)
2337
}
2438

2539
@TestfunonInitialState_handles_logging_exceptions() {

‎workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/WorkflowInterceptorTest.kt‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,63 @@ internal class WorkflowInterceptorTest {
175175
intercepted.render("props","string",RenderContext(fakeContext, workflow))
176176
}
177177

178+
@Testfunintercept_intercepts_onSessionCancelled() {
179+
val recorder=RecordingWorkflowInterceptor()
180+
val session=object:WorkflowSession {
181+
overrideval identifier:WorkflowIdentifier=TestWorkflow.identifier
182+
overrideval renderKey:String=""
183+
overrideval sessionId:Long=0
184+
overrideval parent:WorkflowSession?=null
185+
overrideval runtimeConfig:RuntimeConfig=RuntimeConfigOptions.DEFAULT_CONFIG
186+
overrideval workflowTracer:WorkflowTracer?=null
187+
overrideval runtimeContext:CoroutineContext=EmptyCoroutineContext
188+
}
189+
190+
recorder.onSessionCancelled<String,String,String>(
191+
cause=null,
192+
droppedActions= emptyList(),
193+
session= session
194+
)
195+
196+
// SimpleLoggingWorkflowInterceptor logs "onInstanceStarted" for onSessionCancelled
197+
assertEquals(
198+
listOf("END|onInstanceStarted"),
199+
recorder.consumeEventNames()
200+
)
201+
}
202+
203+
@Testfunintercept_passes_dropped_actions_to_onSessionCancelled() {
204+
var capturedDroppedActions:List<WorkflowAction<*,*,*>>?=null
205+
val interceptor=object:WorkflowInterceptor {
206+
overridefun <P,S,O>onSessionCancelled(
207+
cause: kotlinx.coroutines.CancellationException?,
208+
droppedActions:List<WorkflowAction<P,S,O>>,
209+
session:WorkflowSession
210+
) {
211+
capturedDroppedActions= droppedActions
212+
}
213+
}
214+
val session=object:WorkflowSession {
215+
overrideval identifier:WorkflowIdentifier=TestWorkflow.identifier
216+
overrideval renderKey:String=""
217+
overrideval sessionId:Long=0
218+
overrideval parent:WorkflowSession?=null
219+
overrideval runtimeConfig:RuntimeConfig=RuntimeConfigOptions.DEFAULT_CONFIG
220+
overrideval workflowTracer:WorkflowTracer?=null
221+
overrideval runtimeContext:CoroutineContext=EmptyCoroutineContext
222+
}
223+
val testAction= action<String,String,String>("TestAction") { state="modified" }
224+
225+
interceptor.onSessionCancelled(
226+
cause=null,
227+
droppedActions=listOf(testAction),
228+
session= session
229+
)
230+
231+
assertEquals(1, capturedDroppedActions!!.size)
232+
assertEquals("TestAction", capturedDroppedActions!![0].debuggingName)
233+
}
234+
178235
privatevalWorkflow<*,*,*>.session:WorkflowSession
179236
get()=object:WorkflowSession {
180237
overrideval identifier:WorkflowIdentifier=this@session.identifier

‎workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/ChainedWorkflowInterceptorTest.kt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ internal class ChainedWorkflowInterceptorTest {
7070
session:WorkflowSession
7171
) {
7272
events+="started1"
73+
// We can't use onSessionCancelled because this is completed when the coroutine from
74+
// launch() below finishes, so onSessionCancelled is never called by the runtime.
7375
workflowScope.coroutineContext[Job]!!.invokeOnCompletion {
7476
events+="cancelled1"
7577
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp