I have the same problem you had sometime ago:
"Getting errors with remote actor deployment in Akka 2.0 RC2"
How did yousolve it? I'm using Akka 2.1.2, but I think my problem is the concept.
I create the actor:
ActorRef actorOf = system.actorOf(new Props(HelloWorld.class), "injbct");
and then in other jvm I try to lookup it up :
ActorRef actorFor = system.actorFor("akka://KSystem#127.0.0.1:2552/user/injbct");
Regards, José
I have discovered that if you are accessing a remote actor in the same machine the localhost address of 127.0.0.1 or the machine's actual IP address must be used in both the configuration of the remote actor and the actor declaration in the actor user, i.e. they cannot be mixed.
The remote actor config
remote {
transport = "akka.remote.netty.NettyRemoteTransport"
netty {
hostname = "127.0.0.1"
port = 2554
Considering the machine to have an IP address of 1.2.3.4, then
This works
val workerRouter =
context.actorFor("akka://PrimeWorkerKernel#127.0.0.1:2554/user/PrimeWorkerActor")
This does not and results in a connection refused
val workerRouter =
context.actorFor("akka://PrimeWorkerKernel#1.2.3.4:2554/user/PrimeWorkerActor")
For starters, you should read the Akka Remoting documentation. Then, make sure you have the remoting dependency in your pom file:
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_2.10</artifactId>
<version>2.1.4</version>
</dependency>
Then, both sides (the calling side and the receiving side will need to have remoting config in their application.conf files similar to the example in the remoting docs:
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
transport = "akka.remote.netty.NettyRemoteTransport"
netty {
hostname = "127.0.0.1"
port = 2552
}
}
}
You'll notice that the actor ref provider has been set to the RemoteActorRefProvider as opposed to the default LocalActorRefProvider. Without this on the sending actor side, things won't work. You'll also see that netty binding info has been setup and this is really important on the receiving actor side so that ActorSystem is listening for remote connections and messages. If you follow the steps in the docs and start up your receiving actor system as ActorSystem("KSystem") then things should work for you.
Related
I have a Java service running on 3 different ec2 instances. They form a cluster using Hazelcast. Here's part of my cluster.xml configuration:
<join>
<multicast enabled="false"></multicast>
<tcp-ip enabled="false"></tcp-ip>
<aws enabled="${AWS_ENABLED}">
<iam-role>DEFAULT</iam-role>
<region>us-east-1</region>
<security-group-name>sec-group-name</security-group-name>
<hz-port>6100-6110</hz-port>
</aws>
</join>
Here's the log message that the discovery is successful:
[3.12.2] (This is the hazelcast version)
Members {size:3, ver:31} [
Member [10.0.3.117]:6100 - f5a9d579-ae9c-4c3d-8126-0e8d3a1ecdb9
Member [10.0.1.32]:6100 - 5799f451-f122-4886-92de-e351704e6980
Member [10.0.1.193]:6100 - 626de40a-197a-446e-a44f-ac456a52d118 this
]
vertxInstance.sharedData() is working fine, meaning we can cache data between the instances.
However, the issue is when publishing messages to the instances using the vertx eventbus:
this.vertx.eventBus().publish(EventBusService.TOPIC, memberId);
and having this listener:
eventBus.consumer(TOPIC, event -> {
logger.warn("Captured message: {}", event.body());
});
This configuration works locally, the consumer get's the messages, but once deployed to AWS it doesn't work.
I have tried setting up the host explicitly just for test, but this does not work either:
VertxOptions options = new VertxOptions();
options.setHAEnabled(true);
options.getEventBusOptions().setClustered(true);
options.getEventBusOptions().setHost("10.0.1.0");
What am I doing wrong and what are my options to debug this issue further?
eventbus communication does not use the cluster manager, but rather direct tcp connections
Quote from this conversation: https://groups.google.com/g/vertx/c/fCiJpQh66fk
The solution was to explicitly set the public host and port options for the eventbus:
vertxOptions.getEventBusOptions().setClusterPublicHost(privateIpAddress);
vertxOptions.getEventBusOptions().setClusterPublicPort(5702);
We need to set Eureka server URL at client application from startup code, but it seems there is no way how to do it.
We have a mechanism how to discover Eureka server on network by UDP multicast broadcasting. Server sends response back to the client with information about IP address and port where Eureka server is running. But we don't know how to set this URL in Eureka client application from code. It seems the only way how to set Eureka server URL is the property eureka.client.serviceUrl.defaultZone in application.property file.
// Server - start a new thread with UDP packet detection and reply mechanism
LocationService.listenAndReplyToEurekaClients(thisServerPort);
// Server - application start
SpringApplication.run(EurekaServerApplication.class, args);
// Client - send UDP packet and receive reply with Eureka server IP and port
Response response = LocationService.findEurekaServerAddress(5, 3, TimeUnit.SECONDS);
var hostProtocol = "http";
var eurekaUrl = new URL(
hostProtocol,
response.getEurekaAddress(),
response.getEurekaPort(),"").toString();
We would like to set this eurekaURL to the client before it starts registering to Eureka server.
In this case, we can do following things-
Extend EurekaClientConfigBean and override getEurekaServerServiceUrls method. Method returns a List of String which is nothing but list of all the URLS, of eureka instances. You need to set the URL here from your response which has IP and port.
Later create the discovery client using- DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config). (Its going to be a Bean for sure).
That should work.
You can create ApplicationInfoManager as-
ApplicationInfoManager applicationInfoManager =
initializeApplicationInfoManager(webAppInstanceConfig);
Where WebAppInstanceConfig is-
class WebAppInstanceConfig extends MyDataCenterInstanceConfig {// Override all the needed properties from MyDataCenterInstanceConfig}
I have for legacy reasons a Java activeMQ implementation of the Broker/Publisher over vanilla tcp transport protocol. I wish to connect a Python client to it, however all the "stomp" based documentation doesn't seem to have it, not over the stomp protcol, and when I try the basic examples I get the error on the Java Broker side:
[ActiveMQ Transport: tcp:///127.0.0.1:62860#5001] WARN org.apache.activemq.broker.TransportConnection.Transport - Transport Connection to: tcp://127.0.0.1:62860 failed: java.io.IOException: Unknown data type: 80
The Broker code is very vanilla in Java:
String localVMurl = "vm://localhost";
String remoterURL = "tcp://localhost:5001";
BrokerService broker = new BrokerService();
broker.addConnector(localVMurl);
broker.addConnector(remoterURL);
broker.setAdvisorySupport(true);
broker.start();
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(localVMurl+"?create=false");
Connection connection = connectionFactory.createConnection();
and the Python just fails. I can't seem to find anything online using just basic "tcp://localhost:" connections from Python. Am I doing something wrong here?
import stomp
class MyListener(stomp.ConnectionListener):
def on_error(self, headers, message):
print('received an error "%s"' % message)
def on_message(self, headers, message):
print('received a message "%s"' % message)
conn = stomp.Connection(host_and_ports = [('localhost', 5001)])
conn.start()
conn.connect('admin', 'password', wait=True)
and I get the error:
IndexError: list index out of range
Without seeing the broker configuration it is a bit tricky to answer but from the error I'd guess you are trying to connect a STOMP client to the OpenWire transport which won't work, you need to have a STOMP TransportConnector configured on the broker and point the STOMP client there.
See the ActiveMQ STOMP documentation.
To add STOMP support for an embedded broker you'd do something along the lines of:
brokerService.addConnector("stomp://0.0.0.0:61613");
I am developing a game in Java using RMI for all network communication. RMI allows me to call method on my server, but it is not enough for me. I also want the server to be able to spread message among connected clients.
My clients look up for the server (it's interface extends Remote) and register on it. It allows the server to know who is connected. My clients also implement an interface that extends Remote. Here is some part of my code:
Interfaces declaration:
public interface IServer extends Remote {
void connect(IClient Client) throws RemoteException, ExistingItemException;
//...
}
public interface IClient extends Remote {
public void notify(Notification Notification) throws RemoteException;
//...
}
Server side:
//int RMIPort = 1099, ServerPort = 1100;
IServer Server = new RMIServer();
IServer Proxy = (IServer) UnicastRemoteObject.exportObject(Server, ServerPort);
LocateRegistry.createRegistry(RMIPort).rebind("//" + LocalIP + ":" +
RMIPort + "/xxx", Proxy);
Client side:
//Sets the local reference to IServer and creates the IClient
setInstance(new Client(Login, (IServer) LocateRegistry.getRegistry(RemoteIP).
lookup("//" + RemoteIP + ":" + RMIPort + "/xxx")));
//Gets the IClient and makes it available for the IServer to call notify(...)
Proxy.connect((IClient) (UnicastRemoteObject.exportObject(getInstance(), 0)));
This solution works in local but doesn't when I'm trying to use it through Internet.
I have setup my router to expose my computer to a fix IP address and forward the 1099 and 1100 ports. This solution allow other developers to "lookup" my server and get a valid and usable Proxy, but it doesn't allow them to export their IClient. It seems that the JVM tries to export the object to their local network and the execution stops here.
So, I have tried to pass -Djava.rmi.server.hostname=my-external-IP JVM argument both local for my server and remote for clients. Doing so, exportObject throws a ConnectException to the remote ip instead of local one.
Forget it. Using callbacks over the Internet requires every client to configure his firewall/NAT box/whatever to allow inbound connections and probable port forwarding. Many of them aren't configurable at all, and many of them are run by net admins who just won't do it.
NB you would also have to export on a fixed port.
There is an alternative:
http://dev.root1.de/projects/simon/wiki#Why-SIMON-is-better-than-
The protocol is not compatible to RMI, but the usage is almost the same. Changing from RMI to SIMON is typically not that hard. I heared from users that switching to SIMON took just 30min.
You might think about alternative solution than using RMI, because I believe it was designed for Intranet applications (i.e. Enterprise application within a local network) not Internet.
I would suggest using a long-running TCP connection between the client and the server so at any moment the server wants to communicate back it just pushes a message to this connection.
In this case, initiating the connection will always be the client task. It is very similar to how mail clients connects to imap or pop3 server.
I want to build an actor system that has a common server at a static IP address and port. There will be many clients that know the server's address. The server doesn't know the IP addresses of the clients.
Configuration of the server:
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
transport = "akka.remote.netty.NettyRemoteTransport"
netty {
hostname = "46.38.232.161"
port = 2552
}
}
}
Configuration of the client:
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
transport = "akka.remote.netty.NettyRemoteTransport"
netty {
port = 2553
}
}
}
A client may come from the entire internet. Now I want to send messages from actors on the client to actors on the server. How does the server know, where to send back his messages? When I send ActorPaths to the server, so he would know the corresponding client's address, these don't contain the client's IP address.
akka.remote.netty.hostname property may be set inside your application.conf, to a reachable IP address or resolvable name, in a case you want to communicate across the network. Actually your "client" nodes will also be a servers, when using Akka.
In a case if address is unknown at app start, consider this code fragment from Akka documentation:
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
val customConf = ConfigFactory.parseString("""
akka.actor.deployment {
/my-service {
router = round-robin
nr-of-instances = 3
}
}
""")
// ConfigFactory.load sandwiches customConfig between default reference
// config and default overrides, and then resolves it.
val system = ActorSystem("MySystem", ConfigFactory.load(customConf))
Actor has a method called sender that can be called in the actor's receive method to get a reference to the actor (ActorRef) that sent the current message. The ActorRef has an ActorPath which has a RootActorPath which has an Address which contains the host and port of the ActorSystem where the actor lives.