What's the "right" way to get a statechart's current configuration from outside the statechart given the env returned from com.fulcrologic.statecharts.simple/simple-env ?
I've come up with (get-in @(get-in env [::sc/working-memory-store :storage]) [session-id ::sc/configuration]) but that seems rather clunky.
(there's no fulcro involved here btw)
look in the environment ns I think
ah, but you’re right you’lll need to pull the active working memory
(if you’re not in the context of a statechart expression)
you can use the protocols for that part (insead of the direct get-in)
I tried that, specifically the current-configuration function, but yea, what you said.
Ah ok, I'll take a look there.
So, I am not remembering specifically, and it could be a hole in the API
Also look here, which isn’t meant to be “public” https://github.com/fulcrologic/statecharts/blob/main/src/main/com/fulcrologic/statecharts/algorithms/v20150901_impl.cljc#L746
I’ll look in a bit. have a meeting right now
So, I should have documented this in https://fulcrologic.github.io/statecharts/#_working_memory_and_identity
What you’re looking for is
(let [{::sc/keys [configuration]} (sp/get-working-memory working-memory-store env session-id)]where the working memory store itself is usually stored in the env as well. (pull it out to use as an arg).
The environment ns is meant to be using with live envs in expressions in the chart, whereas outside of the chart you’re basically just working with the overall “setup” (env is unfortunately used to refer to both the configuration environment AND the runtime session processing environment). I should clarify this in the docs if I haven’t
Just to give some more clarity about another complication: Here’s the Malli schema of the configuration env:
(>def ::sc/env [:map {:closed false}
::sc/data-model
::sc/event-queue
::sc/statechart-registry ; how to look up machine definitions
::sc/execution-model
;; These are only needed if you are supporting self-running systems with a self-running event queue
;; or invocations.
[::sc/working-memory-store {:optional true}] ; session-id -> persistence of wmem
[::sc/processor {:optional true}] ; The statechart algorithms
[::sc/invocation-processors {:optional true}]]) ; Invocation support
note that the working memory store is OPTIONAL. The processing implementation is a pure function old-statechart-state -> F(event) -> new-statechart-state. Running it in the “simple env” sets it up so you have an event queue and working memory store to make your life easier, but someone else might just want implement things around the storage/progress of states differently.
So, providing functions that assume there is going to be a working memory store and event queue for “running the world” is not the only way to do it.
That said, I really should figure out where to put some support functions that assume you’re going to to the common/easy thing I use it the way I’ve made for you.like a ns called standard-processing-model or something perhaps not so wordy?
At my primary business I have server-side long-running statecharts for things like subscription management. In those I use a working memory store that serializes the working memory of a chart to an SQL table using nippy, and my event queue is also implemented as an SQL table, where there are many threads on many nodes that look for events that are “ready to fire”, and those event processing threads coordinate to prevent processing the same event twice. Getting the current configuration still works as I described above, though, since my SQL event queue and SQL memory store both implement the protocols.
ok, so I added a runtime ns. Released in 1.2.14. Includes helpers for making a processing env, getting the current config, and getting session data.
Thank you for this, made the shutdown hook I am using much simpler to pull a websocket out of the statechart-local data to close it properly.
Just released 1.2.15…added a send! helper as well. Happy to add more. Really my intention was for people just to use the protocols for the most part, but these are nicer.
I'm curious why in the session-data function you did not use when-let? You have a let then a when. Just wondering if there is a reason to seperate them.
because there is a destructuring
Am I right on that?
I’m sleepy
(when-let [{:keys [x]} {:y 3}]
(println "Foo"))
prints fooI’m not checking if there is a MAP on the right, but if there’s a key in the map
(macroexpand-1 '(when-let [{:keys [x]} {:y 3}]
(println "Foo")))
=> (clojure.core/let [temp__5804__auto__ {:y 3}]
(clojure.core/when temp__5804__auto__
(clojure.core/let [{:keys [x]} temp__5804__auto__] (println "Foo"))))
gotta be careful with those destructurings 😄
There is no destructure there
(let [penv (processing-env env session-id)]
(when penv
(sp/get-at data-model penv data-path)))oh that one 😄
I think I originally had a destructuring and refactored it 😛
Anyways I was just curious, it's working great and thank you for the new namespace I am already refactoring some sends to make them simpler than my current usage.
(I wrote that one first, and the refactored it when I wrote processing-env as a helper)
like I said…sleepy
been up since 3am
and it’s 8pm. so past my bedtime
refactored and pushed 🙂 Thanks for the code review!