In Scala, if I register a remote actor using alive(0), the actor is registered at a random port.
I can do the registration like this: register('fooParActor, self) in the act method.
Now, on the master/server side, I can select an actor by supplying the port. Do I need to manually scan the ports in order to use random ports?
The problem I am trying to solve is to create n actors on a node and then select them all at a master/server program, e.g. start 10 slaves on node x and get a list 10 remote actors at node y.
How is this done?
There's no need to register various ports for the actors. Instead you need one port for the whole actor system - more precisely the akka kernel (that the server needs to know too). See this page of the documentation for how all of this works in detail.
In order to select a remote actor you can then look it up via its path in the remote actor system, similarly to something like this:
context.actorFor("akka://actorSystemName#10.0.0.1:2552/user/someActorName/1")
In that case, you would have created the n actors as children of the someActorName actor and given them the names 1 to n (so you could get the others via .../someActorName/2, .../someActorName/3 and so on).
There's no need to randomize anything at all here and given how you described the problem, there is also no need for randomization within that. You simply start the 10 actors up and number them from 1 to 10. Any random numbers would just unnecessarily complicate things.
As for really random ports I can only agree with sourcedelica. You need a fixed port to communicate the random ones, or some other way of communications. If someone doesn't know where to communicate to due to the random port it simply won't work.
You need to have at least one ActorSystem with a well known port. Then the other ActorSystems can use port 0 to have Akka assign a random port. The slave ActorSystems will have actors register with an actor on the Master so it knows all of the remote systems.
If you absolutely need to have your master use a random port it will need to communicate its port out of band (using a shared filesystem or database).
Related
I'm developing a real-time Phoenix App using it's Channel and Socket modules. The App consists of a few processes and GenServers. I have a use case, where on an event (which is an API call from a microservice), I need to broadcast messages to all different topics on my channel on different timestamps. I have achieved this using Process.send_after(..) on my local machine for now. But my doubt is:
On a fleet of machines, because the API call will hit only a single machine in the cluster,
other machines wouldn't be able to send the broadcast messages. And this would lead to inaccuracy. How can I let all the machines know of this particular event? Or am I doing it wrong?
Assuming you know the names of nodes in the cluster, you might loop nodes, calling Node.spawn/2 on each:
def broadcast(msg) do
Process.send_after ...
end
def broadcast_everywhere(msg) do
Enum.each(#nodes, fn node ->
# if not node == Node.self do
Node.spawn node, fn ->
Broadcaster.broadcast(msg)
end
# end
end)
end
Uncomment the commented lines if the current node was already served, and [probably] somehow ensure the nodes are connected and alive upfront.
Also, Node.spawn_link/* might be worth to take a glance at.
If I want to use (UDP) sockets as an inter-process communication mechanism on a single PC, are there restrictions on what I can set up due to the two endpoints having the same IP address?
I imagine that in order to have two processes A and B both listening on the same IP/port address, SO_REUSADDR would be necessary - correct? And even though that might conceptually allow for full duplex comms over a single socket, there are other questions I have if I try to go full duplex:
would I end up receiving my own transmissions, and have to filter them out?
would I be exposing myself to other processes injecting spurious or malicious data into my sockets due to the use of SO_REUSEADDR... or do I face this possibility simply by using (connectionless) UDP?
how would things be different (in an addressing/security/restrictions sense) if I chose to use TCP instead?
I'm confident that there is a viable solution using two sockets at each end (one for A -> B data, one for B ->A data)... but is there a viable solution using a single socket at each end? Would there be any clear advantages to using one full-duplex socket per process if it is possible?
The question arises from a misunderstanding. The misunderstanding arises from reading variable names like receivePort and sendPort with different values, and reading them as if they have an implicit link to the socket at the local end. This might make one (mistakenly) believe that two sockets are being used, or must be used - one for send, one for receive. This is wrong - a single socket (at each end) is all that is required.
If using variables to refer to ports on a single host, it is preferable to name them such that it is clear that one is local or pertaining to "this" process, and the other is remote or peer and pertains to the address of a different process, despite being on the same local host. Then it should be clearer that, like any socket, it is entirely possibly to support both send and receive from the single socket with its single port number.
In this scenario (inter-process communication on the same host necessarily using different port numbers for the single socket at each end) all the other questions (SO_REUSEADDR, TCP vs UDP and receiving one's own transmissions) are distractions arising from the misunderstanding.
I have a process A that needs to send a message to all process of type B that are running. The process A doesn't know about these other processes, they can be created and destroyed depending on external factors, thus I can have a varying number of process of type B running.
I thought I could use an UDP socket in the process A to send messages to a port P and have all my processes of type B to listen to this port P and receive the a copy of the message.
Is that possible?
I am working with Linux OpenWRT.
I am trying with LuaSockets, but I am getting a "address already in use" error. It seems that I can not have multiples applications to listen to the same port ?
Thanks for your help
It could be useful to use shared memory if all the processes are local to a single machine.
Have a look at http://man7.org/linux/man-pages/man7/shm_overview.7.html for an explanation.
In short you will need the master process to create a shared memory region and write the data into it. The slave processes can then check the data in the memory region and if it has been changed act upon it. This is however just one of many ways to accomplish this problem. You could also look into using pipes and tee.
I have a setup with two Erlang nodes on the same physical machine, and I wanna be able to send large files between the nodes.
From the symptoms I see it looks like there is only one Tcp connection between the nodes, and sending the large binary across stops all other traffic, is this the case?
And even more interesting is there a way of making the vm use several connections between the nodes?
Yeah, you only get 1 connection, according to the manual
The handshake will continue, but A is informed that B has another
ongoing connection attempt that will be shut down (simultaneous
connect where A's name is greater than B's name, compared literally).
Not sure what "big" means in the question, but generally speaking (and imho), it might be good to setup a separate tcp port to handle the payloads, and only use the standard erlang messages as a signaling method (to negotiate ports, setup a listener, etc), like advising there's a new incoming payload and negotiate anything needed.
Btw, there's an interesting thread on the same subject, and you might try tunning the net_* variables to see if they help with the issues.
hope it helps!
It is not recommended to send large messages between erlang nodes,
http://learnyousomeerlang.com/distribunomicon
Refer to "bandwidth is infinite" section, I would recommend use something else like GFS so that you don't lose the distribution feature of erlang.
I know, that if I use a consistent hashing group router, it will always rout to the same registered routees.
So I wrote my application, with a few routees on there own routee-nodes and a public-node with a router, which is reachable by the client.
If the client sends a message it is routed as it should be and it works fine.
Now what I want to do is, add more public-nodes with thier own router that provides the same sending/routing behavior as every other public-node.
What I mean is, that it should not matter if a client sends message XYZ to public-node A, B or C. It should always go to the same routee-node.
At first I thought that akka may provides this behavior by default, because:
I used a group and not a pool router, so everyone knows the same routees
I leared that cluster nodes could be ordered
So I assumed that the routees list is ordered and the different routers map the same keys to the same routees. But testing showed me that I was wrong.
So, is there way in akka to achieve this behavior? Thanks.
As I expected, this behavior shoud be the standart for consistent hashing group routers and it is a bug in the akka-cluster package (current version 2.3.0-RC1)
See this tickt and this google-group post for more details.