MailboxProcessor.PostAndReply design choice - f#

Looking at:
member this.PostAndReply : (AsyncReplyChannel<'Reply> -> 'Msg) * ?int -> 'Reply
I can't figure out why the signature looks so counter-intuitive to me. What we want to do is posting a message to an agent, and wait for a reply.
Why do we have to give him a weird function as a 'message'?
See again this MSDN snippet:
let rec loop() =
printf "> "
let input = Console.ReadLine()
printThreadId("Console loop")
let reply = agent.PostAndReply(fun replyChannel -> input, replyChannel)
if (reply <> "Stopping.") then
printfn "Reply: %s" reply
loop()
else
()
loop()
I'd rather prefer something like this:
member this.PostAndReply : 'Msg * ?int -> 'Reply
Thanks

This type signature looks pretty confusing when you see it for the first time, but it does make sense.
The F# library design
The idea behind the is that when you call PostAndReply you need to give it a function that:
constructs a message of type 'Msg (to be sent to the agent)
after the F# runtime builds a channel for sending messages back to the caller (channels are represented as values of type AsyncReplyChannel<'Reply>).
The message that you construct needs to contain the reply channel, but the F# library does not know how you want to represent your messages (and so it does not know how you want to store the reply channel in the message). As a result, the library asks you to write a function that will construct the message for the agent after the system constructs the channel.
Your alternative suggestion
The problem with your suggestion is that if PostAndReply had a type 'Msg -> 'Reply, the message that the agent receives after it calls Receive would be of the following type:
'Msg * AsyncReplyChannel<'Reply>
... so every message received to the agent would also have to carry a channel for sending replies back. However, you probably don't want to send a reply back for every received message, so this wouldn't really work. Maybe you could use something like:
'Msg * option<AsyncReplyChannel<'Reply>>
... but that's just getting more complicated (and it still isn't quite right, because you can only reply to some messages from 'Msg, but not to all of them).

Related

How to receive on a list of possible values in erlang or elixir

Is it possible to have a dynamic list of values that can be used in a guard for an erlang receive block.
e.g. I want to write something like
receive
{Ref, Message} when Ref in [Refs] ->
%% Do stuff
In Erlang, the guards are limited to the ones seen in here (no lists:member/2)
Given that the match is run for every message in the mailbox, I'd say that it makes sense to allow only simple checks there.
I see two options here:
Add unwanted messages to a queue in the state, and check that queue before the receive when required (when there's a receive with different clauses).
Include some tag in the messages to receive only those with a matching tag:
receive {Ref, Tag, Message} when Tag == State#st.listen_tag -> ...
You can try
receive
{Ref, Message} when is_reference(Ref) ->
handle_message( lists:member(Ref, Refs), Message );
...
handle_message/2 can be implemented as
handle_message(true, Message) ->
%% do stuff
;
handle_message(false, Message) ->
ignore.

Erlang: how to use gproc

I am a little confused with gproc and Pub/Sub methods( https://github.com/uwiger/gproc#use-case-pubsub-patterns ).
I can't understand how to receive messages from another process.
Example:
-module(ws_handler).
-export([init/2]).
init(Req, Opts) ->
lager:info("WS: init ws handler"),
gproc:reg({p, l, {?MODULE, WSNewMsgKey}}),
{cowboy_websocket, Req, Opts}.
process_data(Data) ->
lager:info("WS: start processing of json data"),
gproc:send({p, l, WSNewMsgKey}, {self(), WSNewMsgKey, Data}).
There are 2 processes, both of them are registered as subscribers. They should share incoming data with each other. I guess that i have to implement some interface/function but docs don't tell which exactly.
I've never used gproc for this, but it certainly seems like two things are missing: a definition of WSNewMsgKey (its never in scope in your snippet above) and a receive clause somewhere to accept the messages sent:
-module(ws_handler).
-export([init/2]).
init(Req, Opts) ->
gproc:reg({p, l, {?MODULE, ws_event}}),
{some_state_blah, Req, Opts}.
notify_peers(Event) ->
gproc:send({p, l, ws_event}, {self(), ws_event, Event}).
...and elsewhere either
handle_info({From, ws_event, Event}, State) ->
ok = handle_ws_event(From, Event).
or in your loop (if you wrote your process by hand):
loop(State) ->
receive
{From, ws_event, Event} ->
ok = handle_ws_event(From, Event),
loop(State);
Whatever ->
% other stuff...
end.
I'm not sure if the message that is sent would be sent by as a call, a cast, or a normal message (I'm assuming either an OTP generic cast, or normal message) -- but it seems that this is what should happen. In all cases, though, you need a well-defined key to identify the category of message being sent, and here I've used the atom 'ws_event' to make this explicit.
As for the details of the snippet above... you appear to be broadcasting the same JSON message to a bunch of processes at once for some sort of processing? I'm not sure what this would do for you -- I can't think of any case where broadcasting raw JSON would be beneficial (unless maybe if the need is to broadcast the JSON outside of the system and you are broadcasting to a bunch of subscribed client socket handlers?). So I'm confused at the context (what are you trying to achieve?).
This appears to be the way the docs intend this to be used -- but I'd have to actually play with it to be certain.

Can you use a list (or other collection) to specify what messages to receive in Erlang?

E.g. suppose I have a list that looks something roughly like this:
Handlers = [{foo, FooHandler}, {bar, BarHandler} | Etc()]
The best that I can come up with is this:
receive
Message ->
Handler = find_matching_handler(Message, Handlers),
Handler(Message)
end
The problem with this is that if Message does not match anything in Handlers, it's too late: I've taken it out of the mailbox.
I guess if there's a way to put a message back into the mailbox (into the save queue) without reordering, then that would take care of it. Simply resending to self() would reorder. It would also not restart the receive, and even if it did, you might get stuck in a spin loop until a message of interest arrives. Is there a way to put a message into the mailbox's save queue?
Another near solution that I thought of was to use match guard, but IIUC, you can only use BIFs in guards, which seems to preclude using find_matching_handler (unless there is a BIF for that).
Another near solution: map matching:
receive
M when Handlers#{M := Handler} -> Handler(M) % booyah?
end
Alas, I have not found an incantation that satisfies Erlang...
Match on the message:
loop() ->
receive
{foo, Data} ->
handle_foo(Data),
loop();
{bar, Data} ->
handle_bar(Data),
loop()
end.
This is the basic way of distinguishing between message forms.
You can also be less direct and match in a function head you pass all messages to:
loop() ->
receive
Message ->
handle_message(Message),
loop()
end.
handle_message({foo, Data}) ->
foo(Data),
ok;
handle_message({bar, Data}) ->
bar(Data),
ok.
A combination of the first and second forms is sort of the way gen_server type callback modules are structured in OTP. The message handlers receive a slightly more complex set of arguments and exist in their own module (the part you write), and the actual receive occurs in the generic gen_server module.
You can use a selective receive pattern to periodcally scan the mailbox for handler messages. Something like this:
check_msg_handlers(Handlers) ->
[check_handler(X) || X <- Handlers],
timer:sleep(500),
check_msg_handlers(Handlers).
check_handler(Handler) ->
receive
{_Handler={M,F}, Msg} ->
M:F(Msg)
after
0 ->
no_msg
end.
Note the receive X -> Y after -> N no_msg end, this is the selective receive. When using a timeout of N=0 it effectively becomes a scan of the mailbox to see if the X message is present or not, i.e. it becomes a non-blocking receive. The order of the messages is preserved after the scan as required in your case.
The LYSE chapter More On Multiprocessing has a section on selective receives that is very good.

Handling WebExceptions properly?

I have the following F# program that retrieves a webpage from the internet:
open System.Net
[<EntryPoint>]
let main argv =
let mutable pageData : byte[] = [| |]
let fullURI = "http://www.badaddress.xyz"
let wc = new WebClient()
try
pageData <- wc.DownloadData(fullURI)
()
with
| :? System.Net.WebException as err -> printfn "Web error: \n%s" err.Message
| exn -> printfn "Unknown exception:\n%s" exn.Message
0 // return an integer exit code
This works fine if the URI is valid and the machine has an internet connection and the web server responds properly etc. In an ideal functional programming world the results of a function would not depend on external variables not passed as arguments (side effects).
What I would like to know is what is the appropriate F# design pattern to deal with operations which might require the function to deal with recoverable external errors. For example if the website is down one might want to wait 5 minutes and try again. Should parameters like how many times to retry and delays between retries be passed explicitly or is it OK to embed these variables in the function?
In F#, when you want to handle recoverable errors you almost universally want to use the option or the Choice<_,_> type. In practice the only difference between them is that Choice allows you to return some information about the error while option does not. In other words, option is best when it doesn't matter how or why something failed (only that it did fail); Choice<_,_> is used when having information about how or why something failed is important. For example, you might want to write the error information to a log; or perhaps you want to handle an error situation differently based on why something failed -- a great use case for this is providing accurate error messages to help users diagnose a problem.
With that in mind, here's how I'd refactor your code to handle failures in a clean, functional style:
open System
open System.Net
/// Retrieves the content at the given URI.
let retrievePage (client : WebClient) (uri : Uri) =
// Preconditions
checkNonNull "uri" uri
if not <| uri.IsAbsoluteUri then
invalidArg "uri" "The URI must be an absolute URI."
try
// If the data is retrieved successfully, return it.
client.DownloadData uri
|> Choice1Of2
with
| :? System.Net.WebException as webExn ->
// Return the URI and WebException so they can be used to diagnose the problem.
Choice2Of2 (uri, webExn)
| _ ->
// Reraise any other exceptions -- we don't want to handle them here.
reraise ()
/// Retrieves the content at the given URI.
/// If a WebException is raised when retrieving the content, the request
/// will be retried up to a specified number of times.
let rec retrievePageRetry (retryWaitTime : TimeSpan) remainingRetries (client : WebClient) (uri : Uri) =
// Preconditions
checkNonNull "uri" uri
if not <| uri.IsAbsoluteUri then
invalidArg "uri" "The URI must be an absolute URI."
elif remainingRetries = 0u then
invalidArg "remainingRetries" "The number of retries must be greater than zero (0)."
// Try to retrieve the page.
match retrievePage client uri with
| Choice1Of2 _ as result ->
// Successfully retrieved the page. Return the result.
result
| Choice2Of2 _ as error ->
// Decrement the number of retries.
let retries = remainingRetries - 1u
// If there are no retries left, return the error along with the URI
// for diagnostic purposes; otherwise, wait a bit and try again.
if retries = 0u then error
else
// NOTE : If this is modified to use 'async', you MUST
// change this to use 'Async.Sleep' here instead!
System.Threading.Thread.Sleep retryWaitTime
// Try retrieving the page again.
retrievePageRetry retryWaitTime retries client uri
[<EntryPoint>]
let main argv =
/// WebClient used for retrieving content.
use wc = new WebClient ()
/// The amount of time to wait before re-attempting to fetch a page.
let retryWaitTime = TimeSpan.FromSeconds 2.0
/// The maximum number of times we'll try to fetch each page.
let maxPageRetries = 3u
/// The URI to fetch.
let fullURI = Uri ("http://www.badaddress.xyz", UriKind.Absolute)
// Fetch the page data.
match retrievePageRetry retryWaitTime maxPageRetries wc fullURI with
| Choice1Of2 pageData ->
printfn "Retrieved %u bytes from: %O" (Array.length pageData) fullURI
0 // Success
| Choice2Of2 (uri, error) ->
printfn "Unable to retrieve the content from: %O" uri
printfn "HTTP Status: (%i) %O" (int error.Status) error.Status
printfn "Message: %s" error.Message
1 // Failure
Basically, I split your code out into two functions, plus the original main:
One function that attempts to retrieve the content from a specified URI.
One function containing the logic for retrying attempts; this 'wraps' the first function which performs the actual requests.
The original main function now only handles 'settings' (which you could easily pull from an app.config or web.config) and printing the final results. In other words, it's oblivious to the retrying logic -- you could modify the single line of code with the match statement and use the non-retrying request function instead if you wanted.
If you want to pull content from multiple URIs AND wait for a significant amount of time (e.g., 5 minutes) between retries, you should modify the retrying logic to use a priority queue or something instead of using Thread.Sleep or Async.Sleep.
Shameless plug: my ExtCore library contains some things to make your life significantly easier when building something like this, especially if you want to make it all asynchronous. Most importantly, it provides an asyncChoice workflow and collections functions designed to work with it.
As for your question about passing in parameters (like the retry timeout and number of retries) -- I don't think there's a hard-and-fast rule for deciding whether to pass them in or hard-code them within the function. In most cases, I prefer to pass them in, though if you have more than a few parameters to pass in, you're better off creating a record to hold them all and passing that instead. Another approach I've used is to make the parameters option values, where the defaults are pulled from a configuration file (though you'll want to pull them from the file once and assign them to some private field to avoid re-parsing the configuration file each time your function is called); this makes it easy to modify the default values you've used in your code, but also gives you the flexibility of overriding them when necessary.

Unable to use Erlang/ets in receive block

I am trying to use Erlang/ets to store/update various informations by pattern matching received data. Here is the code
start() ->
S = ets:new(test,[]),
register(proc,spawn(fun() -> receive_data(S) end)).
receive_data(S) ->
receive
{see,A} -> ets:insert(S,{cycle,A}) ;
[[f,c],Fcd,Fca,_,_] -> ets:insert(S,{flag_c,Fcd,Fca});
[[b],Bd,Ba,_,_] -> ets:insert(S,{ball,Bd,Ba})
end,
receive_data(S).
Here A is cycle number, [f,c] is center flag , [b] is ball and Fcd,Fca, Bd, Ba are directions and angle of flag and ball from player.
Sender process is sending these informations. Here, pattern matching is working correctly which I checked by printing values of A, Fcd,Fca..etc. I believe there is something wrong with the use of Erlang/ets.
When I run this code I get error like this
Error in process <0.48.0> with exit value: {badarg,[{ets,insert,[16400,{cycle,7}]},{single,receive_data,1}]
Can anybody tell me what's wrong with this code and how to correct this problem?
The problem is that the owner of the ets-table is the process running the start/1 function and the default behavior for ets is to only allow the owner to write and other processes to read, aka protected. Two solutions:
Create the ets table as public
S = ets:new(test,[public]).
Set the owner to your newly created process
Pid = spawn(fun() -> receive_data(S) end,
ets:give_away(test, Pid, gift)
register(proc,Pid)
Documentation for give_away/3

Resources