openstack team mailing list archive
-
openstack team
-
Mailing list archive
-
Message #11365
getting started with rpc
Gary, Bob,
I figured since both of you had expressed some interest in the rpc API
for use in Quantum, I would give a quick intro to the API to help get
you started (and CC the openstack list for anyone else that may benefit).
The best way to start is to look at how the code is used in nova. The
public API can be found in nova/rpc/__init__.py. Note that I'm in the
middle of adding more to the public rpc API in this feature branch to
add API versions:
https://github.com/russellb/nova/tree/bp/versioned-rpc-apis
== SERVER SIDE
You can find an example of the server side in nova/service.py:
https://github.com/openstack/nova/blob/master/nova/service.py#L196
This code does a few important things:
1) Create an rpc connection.
2) Create 3 consumers on the connection.
3) Spawn a thread to handle incoming messages.
You'll see that in the nova code, three consumers are created. This is
to set up 3 different messaging patterns. Let's assume that this code
is running for service 'nova-foo'. In that case, self.topic would be 'foo'.
pattern 1:
# Share this same connection for these Consumers
self.conn.create_consumer(self.topic, self, fanout=False)
For pattern 1, all instances of the 'nova-foo' service are creating a
consumer with topic 'foo'. When a message is sent to topic 'foo' using
the client side of the rpc API, it goes to exactly one instance of the
nova-foo service. If AMQP is the messaging backend for rpc, messages to
the 'foo' topic are delivered round-robin.
pattern 2:
node_topic = '%s.%s' % (self.topic, self.host)
self.conn.create_consumer(node_topic, self, fanout=False)
For pattern 2, each nova-foo service is creating its own topic using the
hostname - foo.<host>. This topic is used to target messages to a
specific host.
pattern 3:
self.conn.create_consumer(self.topic, self, fanout=True)
Pattern 3 is a broadcast. The topic is set to 'foo' here, but fanout is
True. When a client sends a fanout message to 'foo', *all* instances of
nova-foo will get the message.
The other important thing here is the meaning of the second argument to
create_consumer(). This is the object that is the target of all rpc
messages. When an rpc message comes in saying to run a method, the code
looks at this object for that method to run.
== CLIENT SIDE
The most important client side functions are:
cast()
call()
fanout_cast()
multicall()
You'll also see cast_to_server() and fanout_cast_to_server(), but you
should probably ignore those for now, as I believe they will be going
away at some point.
cast() is for sending a one-way message.
call() is for sending a message and waiting the return value from the
remote method.
fanout_cast() is a one-way broadcast message.
multicall() isn't actually used anywhere in nova, but it may be useful
at some point. multicall() is a variant of call() that allows the
remote method to return multiple values and allows the client to process
them as they occur. You can think of it as calling a remote generator
and rpc.multicall() returns an iterator to allow you to process those
results as they come in.
Each of these client-side methods take a topic argument which is used
for targeting the message. The message argument is a Python dict in the
form: {'method': remote_method_to_run_as_str, 'args': dict_of_kwargs}.
Note that you don't have to do any explicit creation of a connection for
the client side of this API. It uses a connection pool behind the scenes.
You can search around through nova to find many uses of these functions.
Let me know if you have any questions!
--
Russell Bryant