Skip to content

Commit eacf8da

Browse files
Merge pull request #628 from square/zachklipp/tracing-v2
Rewrite the tracing infrastructure to use a listener-based approach.
2 parents 31ed415 + 25c3697 commit eacf8da

File tree

43 files changed

+2086
-773
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2086
-773
lines changed

kotlin/build.gradle

+2-3
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,8 @@ subprojects {
149149
project.tasks.findByName('check')?.dependsOn 'detekt'
150150

151151
project.configurations.configureEach {
152-
// No module depends on on Kotlin Reflect directly, but there could be transitive dependencies
153-
// in tests with a lower version. This could cause problems with a newer Kotlin version that
154-
// we use.
152+
// There could be transitive dependencies in tests with a lower version. This could cause
153+
// problems with a newer Kotlin version that we use.
155154
resolutionStrategy.force "org.jetbrains.kotlin:kotlin-reflect:${versions.kotlin}"
156155
}
157156
}

kotlin/samples/dungeon/app/src/main/java/com/squareup/sample/dungeon/MainActivity.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package com.squareup.sample.dungeon
1717

1818
import android.os.Bundle
1919
import androidx.appcompat.app.AppCompatActivity
20+
import com.squareup.workflow.diagnostic.SimpleLoggingDiagnosticListener
2021
import com.squareup.workflow.ui.WorkflowRunner
2122
import com.squareup.workflow.ui.setContentWorkflow
2223

@@ -34,7 +35,8 @@ class MainActivity : AppCompatActivity() {
3435
WorkflowRunner.Config(
3536
workflow = component.appWorkflow,
3637
viewRegistry = component.viewRegistry,
37-
props = "simple_maze.txt"
38+
props = "simple_maze.txt",
39+
diagnosticListener = SimpleLoggingDiagnosticListener()
3840
)
3941
}
4042
}

kotlin/samples/dungeon/common/src/main/java/com/squareup/sample/dungeon/GameWorkflow.kt

+2
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ private class TickerWorker(private val ticksPerSecond: Int) : Worker<Long> {
223223
delay(periodMs)
224224
}
225225
}
226+
227+
override fun toString(): String = "TickerWorker(ticksPerSecond=$ticksPerSecond)"
226228
}
227229

228230
private data class MoveResult(

kotlin/samples/hello-workflow-fragment/src/main/java/com/squareup/sample/helloworkflowfragment/HelloWorkflowFragment.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.squareup.sample.helloworkflowfragment
1717

18+
import com.squareup.workflow.diagnostic.SimpleLoggingDiagnosticListener
1819
import com.squareup.workflow.ui.ViewRegistry
1920
import com.squareup.workflow.ui.WorkflowFragment
2021
import com.squareup.workflow.ui.WorkflowRunner
@@ -23,6 +24,8 @@ private val viewRegistry = ViewRegistry(HelloFragmentLayoutRunner)
2324

2425
class HelloWorkflowFragment : WorkflowFragment<Unit, Unit>() {
2526
override fun onCreateWorkflow(): WorkflowRunner.Config<Unit, Unit> {
26-
return WorkflowRunner.Config(HelloWorkflow, viewRegistry)
27+
return WorkflowRunner.Config(HelloWorkflow, viewRegistry,
28+
diagnosticListener = SimpleLoggingDiagnosticListener()
29+
)
2730
}
2831
}

kotlin/samples/hello-workflow/src/main/java/com/squareup/sample/helloworkflow/HelloWorkflowActivity.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package com.squareup.sample.helloworkflow
1717

1818
import android.os.Bundle
1919
import androidx.appcompat.app.AppCompatActivity
20+
import com.squareup.workflow.diagnostic.SimpleLoggingDiagnosticListener
2021
import com.squareup.workflow.ui.ViewRegistry
2122
import com.squareup.workflow.ui.WorkflowRunner
2223
import com.squareup.workflow.ui.setContentWorkflow
@@ -29,7 +30,10 @@ class HelloWorkflowActivity : AppCompatActivity() {
2930
override fun onCreate(savedInstanceState: Bundle?) {
3031
super.onCreate(savedInstanceState)
3132
runner = setContentWorkflow(savedInstanceState) {
32-
WorkflowRunner.Config(HelloWorkflow, viewRegistry)
33+
WorkflowRunner.Config(
34+
HelloWorkflow, viewRegistry,
35+
diagnosticListener = SimpleLoggingDiagnosticListener()
36+
)
3337
}
3438
}
3539

kotlin/samples/tictactoe/app/src/main/java/com/squareup/sample/mainactivity/MainActivity.kt

+10-6
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ import androidx.test.espresso.IdlingResource
2121
import com.squareup.sample.authworkflow.AuthViewBindings
2222
import com.squareup.sample.gameworkflow.TicTacToeViewBindings
2323
import com.squareup.sample.panel.PanelContainer
24+
import com.squareup.workflow.VeryExperimentalWorkflow
25+
import com.squareup.workflow.diagnostic.SimpleLoggingDiagnosticListener
2426
import com.squareup.workflow.ui.ViewRegistry
2527
import com.squareup.workflow.ui.WorkflowRunner
2628
import com.squareup.workflow.ui.setContentWorkflow
27-
import io.reactivex.disposables.CompositeDisposable
2829
import io.reactivex.disposables.Disposables
2930
import timber.log.Timber
3031

@@ -36,6 +37,7 @@ class MainActivity : AppCompatActivity() {
3637

3738
lateinit var idlingResource: IdlingResource
3839

40+
@UseExperimental(VeryExperimentalWorkflow::class)
3941
override fun onCreate(savedInstanceState: Bundle?) {
4042
super.onCreate(savedInstanceState)
4143

@@ -48,15 +50,17 @@ class MainActivity : AppCompatActivity() {
4850

4951
workflowRunner = setContentWorkflow(
5052
savedInstanceState,
51-
{ WorkflowRunner.Config(component.mainWorkflow, viewRegistry) }
53+
{
54+
WorkflowRunner.Config(
55+
component.mainWorkflow, viewRegistry,
56+
diagnosticListener = SimpleLoggingDiagnosticListener()
57+
)
58+
}
5259
) {
5360
finish()
5461
}
5562

56-
loggingSub = CompositeDisposable(
57-
workflowRunner.renderings.subscribe { Timber.d("rendering: %s", it) },
58-
workflowRunner.debugInfo.subscribe { Timber.v("debug snapshot: %s", it) }
59-
)
63+
loggingSub = workflowRunner.renderings.subscribe { Timber.d("rendering: %s", it) }
6064
}
6165

6266
override fun onSaveInstanceState(outState: Bundle) {

kotlin/samples/todo-android/app/src/main/java/com/squareup/sample/mainactivity/MainActivity.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.squareup.sample.mainactivity
1818
import android.os.Bundle
1919
import androidx.appcompat.app.AppCompatActivity
2020
import com.squareup.sample.todo.TodoListsAppWorkflow
21+
import com.squareup.workflow.diagnostic.SimpleLoggingDiagnosticListener
2122
import com.squareup.workflow.ui.ViewRegistry
2223
import com.squareup.workflow.ui.WorkflowRunner
2324
import com.squareup.workflow.ui.setContentWorkflow
@@ -36,7 +37,10 @@ class MainActivity : AppCompatActivity() {
3637
?: TodoListsAppWorkflow()
3738

3839
workflowRunner = setContentWorkflow(savedInstanceState) {
39-
WorkflowRunner.Config(rootWorkflow, viewRegistry)
40+
WorkflowRunner.Config(
41+
rootWorkflow, viewRegistry,
42+
diagnosticListener = SimpleLoggingDiagnosticListener()
43+
)
4044
}
4145
}
4246

kotlin/workflow-core/src/main/java/com/squareup/workflow/Worker.kt

+5
Original file line numberDiff line numberDiff line change
@@ -359,11 +359,14 @@ private class TimerWorker(
359359

360360
override fun doesSameWorkAs(otherWorker: Worker<*>): Boolean =
361361
otherWorker is TimerWorker && otherWorker.key == key
362+
363+
override fun toString(): String = "TimerWorker(delayMs=$delayMs)"
362364
}
363365

364366
private object FinishedWorker : Worker<Nothing> {
365367
override fun run(): Flow<Nothing> = emptyFlow()
366368
override fun doesSameWorkAs(otherWorker: Worker<*>): Boolean = otherWorker === FinishedWorker
369+
override fun toString(): String = "FinishedWorker"
367370
}
368371

369372
private class WorkerWrapper<T, R>(
@@ -374,4 +377,6 @@ private class WorkerWrapper<T, R>(
374377
override fun doesSameWorkAs(otherWorker: Worker<*>): Boolean =
375378
otherWorker is WorkerWrapper<*, *> &&
376379
wrapped.doesSameWorkAs(otherWorker.wrapped)
380+
381+
override fun toString(): String = "WorkerWrapper($wrapped)"
377382
}

kotlin/workflow-runtime/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ dependencies {
3131
api deps.kotlin.coroutines.core
3232

3333
testImplementation deps.kotlin.test.jdk
34+
testImplementation "org.jetbrains.kotlin:kotlin-reflect:${versions.kotlin}"
3435
}

kotlin/workflow-runtime/src/main/java/com/squareup/workflow/LaunchWorkflow.kt

+25-19
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package com.squareup.workflow
1717

18-
import com.squareup.workflow.debugging.WorkflowDebugInfo
1918
import com.squareup.workflow.internal.RealWorkflowLoop
2019
import com.squareup.workflow.internal.WorkflowLoop
2120
import com.squareup.workflow.internal.unwrapCancellationCause
@@ -140,7 +139,12 @@ fun <PropsT, StateT, OutputT : Any, RenderingT, RunnerT> launchWorkflowForTestFr
140139
beforeStart = beforeStart
141140
)
142141

143-
@UseExperimental(ExperimentalCoroutinesApi::class, FlowPreview::class)
142+
@UseExperimental(
143+
ExperimentalCoroutinesApi::class,
144+
FlowPreview::class,
145+
VeryExperimentalWorkflow::class
146+
)
147+
@Suppress("LongParameterList")
144148
internal fun <PropsT, StateT, OutputT : Any, RenderingT, RunnerT> launchWorkflowImpl(
145149
scope: CoroutineScope,
146150
workflowLoop: WorkflowLoop,
@@ -152,28 +156,31 @@ internal fun <PropsT, StateT, OutputT : Any, RenderingT, RunnerT> launchWorkflow
152156
): RunnerT {
153157
val renderingsAndSnapshots = ConflatedBroadcastChannel<RenderingAndSnapshot<RenderingT>>()
154158
val outputs = BroadcastChannel<OutputT>(capacity = 1)
155-
val debugSnapshots = ConflatedBroadcastChannel<WorkflowDebugInfo>()
156159
val workflowScope = scope + Job(parent = scope.coroutineContext[Job])
157160

158161
// Give the caller a chance to start collecting outputs.
159-
val session = WorkflowSession(
160-
renderingsAndSnapshots.asFlow(),
161-
outputs.asFlow(),
162-
debugSnapshots.asFlow()
163-
)
162+
val session = WorkflowSession(renderingsAndSnapshots.asFlow(), outputs.asFlow())
164163
val result = beforeStart(workflowScope, session)
164+
val visitor = session.diagnosticListener
165165

166166
val workflowJob = workflowScope.launch {
167-
// Run the workflow processing loop forever, or until it fails or is cancelled.
168-
workflowLoop.runWorkflowLoop(
169-
workflow,
170-
props,
171-
initialSnapshot = initialSnapshot,
172-
initialState = initialState,
173-
onRendering = renderingsAndSnapshots::send,
174-
onOutput = outputs::send,
175-
onDebugSnapshot = debugSnapshots::send
176-
)
167+
visitor?.onRuntimeStarted(this)
168+
try {
169+
// Run the workflow processing loop forever, or until it fails or is cancelled.
170+
workflowLoop.runWorkflowLoop(
171+
workflow,
172+
props,
173+
initialSnapshot = initialSnapshot,
174+
initialState = initialState,
175+
onRendering = renderingsAndSnapshots::send,
176+
onOutput = outputs::send,
177+
diagnosticListener = visitor
178+
)
179+
} finally {
180+
// Only emit the runtime stopped debug event after all child coroutines have completed.
181+
// coroutineScope does an implicit join on all its children.
182+
visitor?.onRuntimeStopped()
183+
}
177184
}
178185

179186
// Ensure we close the channels when we're done, so that they propagate errors.
@@ -183,7 +190,6 @@ internal fun <PropsT, StateT, OutputT : Any, RenderingT, RunnerT> launchWorkflow
183190
val realCause = cause?.unwrapCancellationCause()
184191
renderingsAndSnapshots.close(realCause)
185192
outputs.close(realCause)
186-
debugSnapshots.close(realCause)
187193

188194
// If the cancellation came from inside the workflow loop, the outer runtime scope needs to be
189195
// explicitly cancelled. See https://github.com/square/workflow/issues/464.

kotlin/workflow-runtime/src/main/java/com/squareup/workflow/WorkflowSession.kt

+7-4
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,21 @@
1515
*/
1616
package com.squareup.workflow
1717

18-
import com.squareup.workflow.debugging.WorkflowDebugInfo
18+
import com.squareup.workflow.diagnostic.WorkflowDiagnosticListener
1919
import kotlinx.coroutines.flow.Flow
2020

2121
/**
2222
* A tuple of [Flow]s representing all the emissions from the workflow runtime.
2323
*
24-
* Passed to the function taken by [launchWorkflowIn].
24+
* Passed to [launchWorkflowIn]'s `beforeStart` function.
2525
*
26-
* @param debugInfo A stream of [diagnostic information][WorkflowDebugInfo] about the runtime.
26+
* @param diagnosticListener Null by default. If set to a non-null value before `beforeStart`
27+
* returns, that [WorkflowDiagnosticListener] will receive all diagnostic events from the runtime.
28+
* Setting this property after `beforeStart` returns will have no effect.
2729
*/
30+
@UseExperimental(VeryExperimentalWorkflow::class)
2831
class WorkflowSession<out OutputT : Any, out RenderingT>(
2932
val renderingsAndSnapshots: Flow<RenderingAndSnapshot<RenderingT>>,
3033
val outputs: Flow<OutputT>,
31-
val debugInfo: Flow<WorkflowDebugInfo>
34+
var diagnosticListener: WorkflowDiagnosticListener? = null
3235
)

kotlin/workflow-runtime/src/main/java/com/squareup/workflow/debugging/WorkflowDebugInfo.kt

-28
This file was deleted.

0 commit comments

Comments
 (0)