clj-statecharts
clj-statecharts copied to clipboard
Allow cancelling of `:delay`
The :after
keyword can be used to specify a delayed transition, and allows a function that returns a dynamic delay. Would it make sense to cancel the delay if the :delay
function returns nil
?
LIke this (example from the docs)
(defn calculate-backoff
"Exponential backoff, with a upper limit of 15 seconds. Stops retrying after 15 attemtps"
[state & _]
(when (> 15 (:retries state))
(-> (js/Math.pow 2 (:retries state))
(* 1000)
(min 15000))))
(defn update-retries [state & _]
(update state :retries inc))
;; Part of the machine definition
{:states
{:connecting {:entry try-connect
:on {:success-connect :connected}}
:disconnected {:entry (assign update-retries)
:after [{:delay calculate-backoff :target :connecting}]}
:connected {:on {:connection-closed :disconnected}}}}```
technically we can do that, but from a higher level i think it's better to modify the statecharts instead to distinguish "disconnected but retrying" and "disconnected and retry exhausted" states, e.g. by modifying disconnected as a compound state:
:disconnected
{:initial :retrying
:states {:retrying {:entry (assign update-retries)
:after [{:delay calculate-backoff :target :connecting}]}
:retry-exhausted {}
and when transition to disconnected
state, the machine should jump to retry-exhausted
state by checking the :retries
key using some guard
Thank you @lucywang000 for replying and sorry for the delay in responding.
My example was a bit contrived, I just wanted to base it on the existing example in the docs.
My real use case is a general FSM definition that runs several FSM instances. Some of them regularly reload their data whereas others don't. Each FSM instance's :context
has a key that tells whether it's a reloading FSM or not. So the FSM definition has a :delay
function that checks this key. If no reload should happen, my idea was that it should return nil
. Now I instead return 0
and a :guard
follows that cancels the transition if no reload should happen. Which is fine, but the possibility to cancel the :delay
already in the function would be nice.