-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consuming events #45
Comments
Cool to see that you are trying out choice streams! It is unfortunate, but the documentation on them is not yet ready. It is also cool to see that you are working on stuff like the process runner. These will make nice practical examples on how to use Hopac. Basically, you can think of streams as a kind of asynchronous communication channel, similar to multicast channels, that are suitable for one-to-many and many-to-many communication, where each consumer gets to see all the messages and can keep as much of the communication history as desired (usually, though, consumers throw away messages as they consume them). Regarding the streams usage, I think that in some scenarios they could be a good model for the clients of a process runner. In more complex scenarios streams can also be a good model to use internally, but I think that in this case streams are not perhaps the simplest approach. In this case, I think that a simple approach would be to offer the following kind of interface: [<NoComparison>]
type RunningProcess =
{ LineOutput: Alt<Line>
ProcessExited: Alt<ExitResult> } As you can see, there is no mention of streams above. The idea above is simply that let execute (p: Process) : RunningProcess =
let lineOutput = mb ()
let processExited = ivar ()
p.OutputDataReceived.Add <| fun args ->
lineOutput <<-+ args.Data |> start
p.Exited.Add <| fun _ ->
processExited <-= Exited p.ExitCode |> start
if not <| p.Start () then
failwithf "Cannot start %s." p.StartInfo.FileName
p.BeginOutputReadLine ()
{ LineOutput = lineOutput
ProcessExited = processExited } Note that the above example doesn't remove the event handlers from the process object. That should not be a problem unless one tries to reuse process objects rather than just let them be GC'ed. BTW, using Now, a client of that interface can, if so desired, wrap the let lineStream: Streams<Line> =
Streams.foreverJob rp.LineOutput
|> Streams.takeUntil rp.ProcessExited The stream bound to the variable What you would normally do with the It is also possible to go from a stream to an alternative: let lineAlt: Alt<Line> =
Streams.values lineStream The elements from the stream can be read one by one from the alternative returned by |
Thanks! You are right, it seems that streams are overkill here, so I've ended up with let timeoutAlt timeout = Alt.delay <| fun _ ->
match (startTime + timeout) - DateTime.UtcNow with
| t when t > TimeSpan.Zero -> Timer.Global.timeOut t
| _ -> Alt.always() Client can synchronize on it (as well as on About Streams, yes, a well documented example of their usage is very much appreciated. |
What's the best way to consume ordinary
IEvent
(orIObservable
)? This is what I'm trying:Here I basically create two streams based on two events and route each event to a dedicated channel.
Client code is as following:
Besides it does not work, is this code a good use case for streams? Or it's possible to consume event more easily in this case?
The text was updated successfully, but these errors were encountered: