RabbitMQ Article 4: Remote Call and rabbitmq Article 4 call
All we have explained above are local servers. If you need to run a function on a remote computer, wait for the result. This is a different story. This mode is usually called Remote Procedure Call or RPC.
In this chapter, we will use RabbitMQ to build an RPC system, a client, and an extensible RPC server. Now let's get started.
Callback queue
Rpc is generally easier in RabbitMQ. A client sends a request message and a response message to the server. To get a response, we need to send a callback queue address request. As follows:
Message attributes:
The AMQP Protocol has a total of 14 predefined attributes, but most of them are rarely used. The following several attributes may be used more
DeliveryMode: There are two values, one is persistent, the other is short (the second article said)
ContentType: content type: used to describe the MIME type of the encoding. For example, JSON encoding is often used to set this attribute as a good practice: application/json.
ReplyTo: the name of the callback queue is often used.
Correlationid: application related to RPC Response Request
Correlation Id
A response is received in the queue, but it does not know which one the response belongs to. When we use the CorrelationId attribute, we can set it to a unique value for each request, later, when we receive messages in the callback queue, we will see this attribute. If we see an unknown CorrelationId, we can safely ignore the information-it does not belong to our requests. Why should we ignore unknown messages in the callback queue instead of failed errors? This is because of the possibility of a competitive condition on the server side. For example, a confirmation message has not been sent to the request, but the RPC server is down. If this happens, the RPC server will restart again to process the request. This is why repeated responses must be processed on the client.
Requirement
The rpc method is as follows:
1: When the client starts, it creates an anonymous exclusive callback queue.
2: For rpc requests, the client sends two attributes. One is replyTo setting the callback queue, and the other is correlationId setting the unique value for each queue.
3: The request is sent to an rpc_queue queue.
4: The rpc server is a waiting queue request. When receiving a request, the rpc server returns the result returned by the message to the client to end the request.
5: the client waits for data in the callback queue. When a message appears, the client checks the correlationId. If it matches the value returned from the request, the client responds.
Encoding
RPCServer. Java
public class RPCServer { private static final String RPC_QUEUE_NAME = "rpc_queue"; private static int fib(int n) { if (n == 0) { return 0; } if (n == 1) { return 1; } return fib(n - 1) + fib(n - 1); } public static void main(String[] args) throws IOException, InterruptedException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null); channel.basicQos(1); QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume(RPC_QUEUE_NAME, false, consumer); System.out.println("RPCServer Awating RPC request"); while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); BasicProperties props = delivery.getProperties(); BasicProperties replyProps = new AMQP.BasicProperties.Builder(). correlationId(props.getCorrelationId()).build(); String message = new String(delivery.getBody(), "UTF-8"); int n = Integer.parseInt(message); System.out.println("RPCServer fib(" + message + ")"); String response = "" + fib(n); channel.basicPublish( "", props.getReplyTo(), replyProps, response.getBytes()); channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); } }}
Simple server code
1: establish connections, channels, and queues
2: We may run multiple server processes. To relieve the load on the server, we set channel. basicQos (1 );
3: We use basicconsume to access the queue. Then go to the loop, where we wait for the request message, process the message, and then send a response.
RPCClient. java
public class RPCClient { private Connection connection; private Channel channel; private String requestQueueName = "rpc_queue"; private String replyQueueName; private QueueingConsumer consumer; public RPCClient() throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); connection = factory.newConnection(); channel = connection.createChannel(); replyQueueName = channel.queueDeclare().getQueue(); consumer = new QueueingConsumer(channel); channel.basicConsume(replyQueueName, true, consumer); } public String call(String message) throws IOException, InterruptedException { String response; String corrID = UUID.randomUUID().toString(); AMQP.BasicProperties props = new AMQP.BasicProperties().builder() .correlationId(corrID).replyTo(replyQueueName).build(); channel.basicPublish("", requestQueueName, props, message.getBytes("UTF-8")); while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); if (delivery.getProperties().getCorrelationId().equals(corrID)) { response = new String(delivery.getBody(), "UTF-8"); break; } } return response; } public void close() throws Exception { connection.close(); } public static void main(String[] args) throws Exception { RPCClient rpcClient = null; String response; try { rpcClient = new RPCClient(); System.out.println("RPCClient Requesting fib(20)"); response = rpcClient.call("20"); System.out.println("RPCClient Got '" + response + "'"); } catch (Exception e) { e.printStackTrace(); } finally { if (rpcClient != null) { rpcClient.close(); } } }}
Client code explanation
1: Establish a connection and channel, and declare the reply of a unique "Callback" queue
2: we subscribe to the callback queue to get the RPC response.
3: Define a call method to send the current callback request.
4: generate a unique correlationid and capture the appropriate response through the while loop.
5: We send two request attributes, replyTo and correlationId.
6: wait until a proper response arrives.
7: The while loop is a very simple task. For each response message, it checks whether there is a correlationid and then performs matching. Then, respond.
8: Finally, return the response to the client.