I have an actor in local machine and an actor in remote machine. Is it possible to pattern match using Discriminating Union of remote actor with local actor. Here is what I am trying with,
Remote actor:
match msg with
| Task1 msg -> printf "done"
| Task2 msg -> printf "completed"
Local actor:
remoteActor <! Task1 "yes"
I want to send an message from local actor to remote actor like this. But I am unable to send Task1 type from local actor. Any help is appreciable
Thanks in advance.
Akka.NET v1.4 uses Newtonsoft's JSON serializer by default, which doesn't work well with discriminated unions. If you switch to the new Hyperion serializer, it should work fine. Add the following to your config:
akka {
actor {
serializers {
hyperion = "Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion"
}
serialization-bindings {
"System.Object" = hyperion
}
}
}
You can then send and receive discriminated unions with no problems. Hyperion will become the default serializer in Akka.NET v1.5.
Related
Akka.Net:
Why does the actorOf function NOT require a function input that has a Actor<_> as a parameter?
It appears that the actorOf2 function DOES require a Actor<_> parameter.
The context of how these functions are called are the following:
let consoleWriterActor = spawn myActorSystem "consoleWriterActor" (actorOf Actors.consoleWriterActor)
let consoleReaderActor = spawn myActorSystem "consoleReaderActor" (actorOf2 (Actors.consoleReaderActor consoleWriterActor))
let consoleReaderActor (consoleWriter: IActorRef) (mailbox: Actor<_>) message =
...
let consoleWriterActor message =
...
The signature of actorOf is the following:
('Message -> unit) -> Actor<Message> -> Cont<'Message,'Returned>
The signature of actorOf2 is the following:
(Actor<Message> -> 'Message -> unit) -> Actor<Message> -> Cont<'Message,'Returned>
Conclusion:
I am new to Akka.net.
Thus, I don't understand why the "Actor<_>" parameter (which I believe represents a mailbox) would not be useful for the actorOf function.
actorOf2 function takes an Actor<_> parameter, which represents an actor execution context (from F# MailboxProcessor it's often called mailbox). It allows for things such as changing actor lifecycle, creating child actors or communicating with message sender.
However sometimes you may want to create actor, that is designed to work as a simple sink for your data i.e. processing the messages and push the result into some external service. This is where actorOf may be useful.
I want to do network requests form a list of endpoints/APIs (not an specific number), then zip the responses into a single data point.
I know the zip operator has the FuncN as combineFunction, but I dont want to do the following because I dont know how many APIs are in the list:
List<API> apis = ...;
Observable.zip(apis.get(0).search("a"), apis.get(1).search("b"), new Func2<Item, Item, List<Item>>() {
...
}
Any ideas?
The function you mention is exactly what you need, it does not require the number of APIs upfront. You do want to use observables to delay the search on the API:
List<API> apis = ...;
Observable<API> apisObs = Observable.from(apis);
List<String> args = ... // list of "a", "b" ordered like the apis' list
Observable<String> argsObs = Observable.from(args);
Zip the delayed API calls (delaying with Observable.just):
Observable<ResultType> results = apisObs.zipWith(
args, (api, arg) -> Observable.just(api.search(arg))
);
Now zip again to wait for completion of all delayed calls created:
Observable.zip(results, new FuncN<ResultType> ...)
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.
I'm new to Erlang and I'm trying to build a simple game server (learning purpose).
I have one client controller (supervisor) that creates multiple client handlers (gen_server). I have also one game controller (supervisor) that creates multiple game handlers (gen_server).
One game handler (game table) will then communicate with several client handlers (players). I create the client handlers like this:
client_handler.erl:
start_link(ClientId, UniqueId) ->
ClientHandlerId = utils:create_id(?MODULE, UniqueId), //client_handler_0
State = #state{client_id = ClientId, client_handler_id = ClientHandlerId},
gen_server:start_link({global, ClientHandlerId}, ?MODULE, State, []).
game_handler.erl:
start_link(ClientHandlerId, GameId, UniqueId) ->
GameHandlerId = utils:create_id(?MODULE, UniqueId), //game_handler_0
State = #state{client_handler_id = ClientHandlerId, game_id = GameId, game_handler_id = GameHandlerId},
gen_server:start_link({global, GameHandlerId}, ?MODULE, State, []).
My problem is that I want to talk between client_handler and game_handler without neither of them knowing about their inner structure. For now I use:
client_handler.erl:
gen_server:cast(game_handler_0, {make_move, MoveData}).
and this works great. However, I would like to use:
client_handler.erl:
game_handler_0:make_move(MoveData)
So I can build separate API:s for each module (only use -export functions). Is this possible?
Best regards,
xqtr
EDIT: typo
Yes, it is considered good practice to abstract away implementation details in that way. Just move the cast call into a function in game_handler.erl, something like:
make_move(UniqueId, MoveData) ->
GameHandlerId = utils:create_id(?MODULE, UniqueId),
gen_server:cast(GameHandlerId, {make_move, MoveData}).
and export make_move/2. (Or perhaps forget about UniqueId, and pass GameHandlerId directly to the make_move function.)
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).