macros: add onStart and onStop

The onStart and onStop macros will be called as actors start and
stop. This can be used to call `quit`, since the async dispatcher
will run empty and raise an error otherwise.
This commit is contained in:
Emery Hemingway 2021-06-30 12:18:57 +02:00
parent 300f0169bb
commit 50afa0107f
3 changed files with 20 additions and 3 deletions

View File

@ -11,6 +11,8 @@ export dataspaces.Facet
export dataspaces.FieldId
export dataspaces.Fields
export dataspaces.addEndpoint
export dataspaces.addStartScript
export dataspaces.addStopScript
export dataspaces.defineObservableProperty
export dataspaces.generateId
export dataspaces.hash
@ -178,4 +180,4 @@ template syndicate*(name: string; dataspaceBody: untyped): untyped =
proc bootProc(rootFacet: Facet) =
proc getCurrentFacet(): Facet {.inject, used.} = rootFacet
dataspaceBody
waitFor bootModule(name, bootProc)
asyncCheck bootModule(name, bootProc)

View File

@ -253,6 +253,8 @@ proc abort(facet; emitPatches: bool) =
for child in facet.children.values:
child.abort(emitPatches)
facet.retractAssertionsAndSubscriptions(emitPatches)
for s in facet.stopScripts: s(facet)
# call stopScripts immediately
proc enqueueScriptAction(actor; action: Action) =
actor.pendingActions.add(action)
@ -342,10 +344,13 @@ proc scheduleScript*(facet; prio: Priority; script: Script[void]) =
proc scheduleScript*(facet; script: Script[void]) =
facet.actor.scheduleTask(pNormal, facet.wrap(script))
proc addStartScript(facet; s: Script[void]) =
proc addStartScript*(facet; s: Script[void]) =
facet.ensureFacetSetup("onStart")
facet.scheduleScript(pNormal, s)
proc addStopScript*(facet; s: Script[void]) =
facet.stopScripts.add(s)
proc addFacet(actor; parentFacet: Option[Facet]; bootScript: Script[void]; checkInScript = false) =
if checkInScript and parentFacet.isSome:
assert parentFacet.get.inScript
@ -530,6 +535,8 @@ proc step(g: Ground) =
if g.dataspace.runTasks():
asyncdispatch.callSoon: step(g)
else:
for actor in g.dataspace.actors.values:
terminate(actor, false)
for sh in g.stopHandlers:
sh(g.dataspace)
reset g.stopHandlers

View File

@ -7,15 +7,17 @@ import syndicate
const
BoxState = RecordClass(label: symbol"box-state", arity: 1)
SetBox = RecordClass(label: symbol"set-box", arity: 1)
# TODO: hide RecordClass behind Assertion and Message types
syndicate "test_dsl":
spawn "box":
field(currentValue, int, 0)
assert(BoxState, currentValue)
assert(BoxState, currentValue.get)
stopIf currentValue.get == 10:
echo "box: terminating"
onMessage(SetBox) do (newValue: int):
# The SetBox message is unpacked to `newValue: int`
echo "box: taking on new value ", newValue
currentValue.set(newValue)
@ -27,3 +29,9 @@ syndicate "test_dsl":
send(SetBox, v+1)
onRetracted(BoxState) do (_):
echo "client: box state disappeared"
onStop:
quit(0) # Quit explicitly rather than let the dispatcher run empty.
runForever()
# The dataspace is driven by the async dispatcher.
# Without `runForever` this module would exit immediately.