Note
asyncmachine-go is a batteries-included graph control flow library (AOP, actor, state-machine).
To read about am-dbg, go to /tools/cmd/am-dbg. This package is about the implementation, not the end-user application.
/tools/debugger
is a cview TUI app with a single state-machine
consisting of:
- input events (7 states)
- external state (25 states)
- actions (18 states)
This state machine features a decent amount of relations within a large number of states and 5 state groups. It's also a good example to see how easily an AM-based program can be controller with a script in /internal/cmd/am-dbg-video.
See states structure and relations
// States map defines relations and properties of states.
var States = am.Struct{
// ///// Input events
ClientMsg: {Multi: true},
ConnectEvent: {Multi: true},
DisconnectEvent: {Multi: true},
// user scrolling tx / steps
UserFwd: {
Add: S{Fwd},
Remove: GroupPlaying,
},
UserBack: {
Add: S{Back},
Remove: GroupPlaying,
},
UserFwdStep: {
Add: S{FwdStep},
Require: S{ClientSelected},
Remove: SAdd(GroupPlaying, S{LogUserScrolled}),
},
UserBackStep: {
Add: S{BackStep},
Require: S{ClientSelected},
Remove: SAdd(GroupPlaying, S{LogUserScrolled}),
},
// ///// Read-only states (e.g. UI)
// focus group
TreeFocused: {Remove: GroupFocused},
LogFocused: {Remove: GroupFocused},
ClientListFocused: {Remove: GroupFocused},
TimelineTxsFocused: {Remove: GroupFocused},
TimelineStepsFocused: {Remove: GroupFocused},
MatrixFocused: {Remove: GroupFocused},
DialogFocused: {Remove: GroupFocused},
Toolbar1Focused: {Remove: GroupFocused},
Toolbar2Focused: {Remove: GroupFocused},
LogReaderFocused: {
Require: S{LogReaderVisible},
Remove: GroupFocused,
},
AddressFocused: {Remove: GroupFocused},
TimelineHidden: {Require: S{TimelineStepsHidden}},
TimelineStepsHidden: {},
NarrowLayout: {
Require: S{Ready},
Remove: S{ClientListVisible},
},
ClientListVisible: {
Require: S{Ready},
Auto: true,
},
StateNameSelected: {Require: S{ClientSelected}},
TimelineStepsScrolled: {Require: S{ClientSelected}},
HelpDialog: {Remove: GroupDialog},
ExportDialog: {
Require: S{ClientSelected},
Remove: GroupDialog,
},
LogUserScrolled: {
Remove: S{Playing, TailMode},
// TODO remove the requirement once its possible to go back
// to timeline-scroll somehow
Require: S{LogFocused},
},
Ready: {Require: S{Start}},
// TODO should activate FiltersFocused
FilterAutoTx: {},
FilterCanceledTx: {},
FilterEmptyTx: {},
FilterSummaries: {},
FilterHealthcheck: {},
// ///// Actions
Start: {Add: S{FilterSummaries, FilterHealthcheck, FilterEmptyTx}},
Healthcheck: {
Multi: true,
Require: S{Start},
},
GcMsgs: {Remove: S{SelectingClient, SwitchedClientTx, ScrollToTx,
ScrollToMutTx}},
TreeLogView: {
Auto: true,
Require: S{Start},
Remove: SAdd(GroupViews, S{TreeMatrixView, MatrixView, MatrixRain}),
},
MatrixView: {Remove: GroupViews},
TreeMatrixView: {Remove: GroupViews},
TailMode: {
Require: S{ClientSelected},
Remove: SAdd(GroupPlaying, S{LogUserScrolled}),
},
Playing: {
Require: S{ClientSelected},
Remove: SAdd(GroupPlaying, S{LogUserScrolled}),
},
Paused: {
Auto: true,
Require: S{ClientSelected},
Remove: GroupPlaying,
},
ToggleTool: {},
SwitchingClientTx: {
Require: S{Ready},
Remove: GroupSwitchedClientTx,
},
SwitchedClientTx: {
Require: S{Ready},
Remove: GroupSwitchedClientTx,
},
ScrollToMutTx: {Require: S{ClientSelected}},
// TODO depend on a common Matrix view
MatrixRain: {},
LogReaderVisible: {
Auto: true,
Require: S{TreeLogView, LogReaderEnabled},
},
LogReaderEnabled: {},
UpdateLogReader: {Require: S{LogReaderEnabled}},
// tx / steps back / fwd
Fwd: {
Require: S{ClientSelected},
},
Back: {
Require: S{ClientSelected},
},
FwdStep: {
Require: S{ClientSelected},
},
BackStep: {
Require: S{ClientSelected},
},
ScrollToTx: {
Require: S{ClientSelected},
Remove: S{TailMode, Playing, TimelineStepsScrolled},
},
ScrollToStep: {
Require: S{ClientSelected},
Remove: S{TailMode, Playing},
},
// client selection
SelectingClient: {
Require: S{Start},
Remove: S{ClientSelected},
},
ClientSelected: {
Require: S{Start},
Remove: S{SelectingClient},
},
RemoveClient: {Require: S{ClientSelected}},
SetCursor: {
Multi: true,
Require: S{Ready},
},
GraphsScheduled: {
Multi: true,
Require: S{Ready},
},
GraphsRendering: {
Require: S{Ready},
},
InitClient: {Multi: true},
}
You can read the source at /tools/debugger and states at /tools/debugger/states.
/tools/debugger/test contains integration tests which use a local worker
instance, which is then controlled with Add1Block
and Add1AsyncBlock from /pkg/helpers
to perform test scenarios. None of the tests ever calls time.Sleep
, as everything is synchronized via asyncmachine's
clock. The local test worker doesn't have UI and uses tcell.SimulationScreen instead.
/tools/debugger/test/remote contains integration tests which
use a remote worker to execute the same suite. The worker has to be started separately using task am-dbg-worker
,
and because it's a regular TUI app, this one has a UI which can be seen and controlled by the user (on top of the test
suite itself).
Because both local and remote workers are state machines, they can export telemetry to a debugger instance. In
aRPC Tutorial one can find a video demo presenting a debugging session of a remote worker. To
activate remote debugging, please set AM_TEST_DEBUG=1
and run task am-dbg-dbg
prior to tests. Remote tests are run
via task test-debugger-remote
.
State schema from /tools/debugger/states/ss_dbg.go.
Go back to the monorepo root to continue reading.