Fork me on GitHub

not sure if this is the right place to ask this, but I was hoping someone might have some words of wisdom regarding best practice for getting visibility into some state being computed inside a go block


Specifically, I have some process running in a go block that responds to commands (think play, pause, stop, etc.). I recur the state each iteration in my go loop, which works great inside the go block, however I'd like to expose that state to others outside the go block (as a read-only type view)


I thought of just calling reset! on an atom before I recur each time, but I don't really like the idea of each go block have a reference to some atom that could be modified elsewhere. I suppose I can simply reset! it and just treat the reset! as an update to the "view" on the status.


I should also mention I'm encapsulating all this in a component (stuartsierra/component). I can therefore do something like pass in an atom at the start of the component lifecycle. The actually go-loop is set as an entry on the component record and kicked off in the component start. In essence, I want to do something like (get-component-status my-running-component)


the actual status is in the state map I mentioned earlier and includes things like a state of running/stopped/paused, friendly names, ids, and things like that. Anyway, I'm not sure what's the preferred approach for giving other pieces of code visibility into this state outside of writing to an external system like a database or log, or just exposing an atom on the component that others can read.


You could expose something that implements clojure.lang.IDeref


@hugesandwich: you could use an atom and have a function which closes over the atom and returns it's value be the only exposed way of getting at the value


go blocks, by design, do not expose their state to outside observers. But you can program your go block to publish its state (such as a progress counter) in any number of ways: modify an Atom, put messages on another channel, write to a log.


I experimented with a sliding out chan with a pub for snapshots but I don't like it


Probably the best solution though since really when you do something equivalent to querying a "process" status, you're really just asking for a snapshot at that point in time anyway and it may have changed by the time you receive the data


I'm not sure if anyone has an opinion on a preferred solution. I'm aware of all the techniques mentioned so far, just looking for pros and cons or something I haven't thought of maybe


Knowing what your observer(s) are looking to do with that state might clarify things


An example use case of what I'm doing - I need to show in a UI something akin to doing "ps -a" where ps is returning a series of states about various go-loops inside a component


sorry I meant components


Needing to know about every change as it happens is different that wanting to be able to view the state at an arbitrary point in time


Each component has a single process loop with an inbox and outbox to be clear. At the moment, I just publish a snapshot of my state (running, paused, muted, etc along with some other values) to a snapshot channel that is part of the component record


If for example you want to pause the go loop processing data, you can send it a "pause" command on its control channel


So my api needs some way of asking is this component's processing loop paused


internally, it's simple because it's sitting in a map


To change the state, I simply alts! on the command channel and input channel with :priority true


it works, but maybe this is a bad design as well


so if I get a command, I update the state accordingly, recur, if I get a value on the inbox, I process it and usually leave things alone regarding the state


@donaldball: Yes, you're right, which is why I thought about atom vs. channel among many other concerns. I try to avoid changing anything in the middle of a go-loop that would cause some sort of split between what the go loop is seeing and what an observer of the component sees. But if I put that information on a channel, there's no guarantee by design when it is seen, so by then things are not a real-time view even with pub/sub. With an atom I could have a watch I suppose but I really don't like each of my components hanging on to an extra atom if possible.


This may be a digression, but clojure agents are designed to combine one-at-a-time processing with visible state.


Thanks. definitely an option. In my case, I'm using myostly the same code server/client so it's simpler to avoid agents