Fork me on GitHub
#core-async
<
2016-02-09
>
hugesandwich16:02:04

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

hugesandwich16:02:26

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)

hugesandwich16:02:28

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.

hugesandwich16:02:09

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)

hugesandwich16:02:54

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.

donaldball17:02:49

You could expose something that implements clojure.lang.IDeref

mccraigmccraig17:02:37

@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

Lambda/Sierra17:02:30

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.

hugesandwich17:02:05

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

hugesandwich17:02:47

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

hugesandwich17:02:27

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

donaldball17:02:10

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

hugesandwich17:02:25

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

hugesandwich17:02:37

sorry I meant components

donaldball17:02:42

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

hugesandwich17:02:19

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

hugesandwich17:02:06

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

hugesandwich17:02:33

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

hugesandwich17:02:54

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

hugesandwich17:02:09

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

hugesandwich17:02:16

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

hugesandwich17:02:15

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

hugesandwich17:02:53

@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.

Lambda/Sierra18:02:59

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

hugesandwich19:02:03

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