<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Apr 29, 2013 at 11:45 AM, Mark McLoughlin <span dir="ltr"><<a href="mailto:markmc@redhat.com" target="_blank">markmc@redhat.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Mon, 2013-04-29 at 10:55 -0400, Doug Hellmann wrote:<br>
><br>
><br>
><br>
> On Mon, Apr 29, 2013 at 10:23 AM, Mark McLoughlin <<a href="mailto:markmc@redhat.com">markmc@redhat.com</a>> wrote:<br>
>         On Mon, 2013-04-29 at 09:39 -0400, Doug Hellmann wrote:<br>
>         ><br>
>         ><br>
>         ><br>
>         > On Mon, Apr 29, 2013 at 7:00 AM, Mark McLoughlin <<a href="mailto:markmc@redhat.com">markmc@redhat.com</a>> wrote:<br>
>         >         On Fri, 2013-04-26 at 15:18 -0400, Doug Hellmann wrote:<br>
>         ><br>
>         >         > We've gone around a few times with ideas for having better driver-parity in<br>
>         >         > the rpc library, so maybe the best thing to do is start by making sure we<br>
>         >         > have all of the requirements lined up. Here's a list of some that I came up<br>
>         >         > with based on existing features and my understanding of the shortcomings<br>
>         >         > (numbered for reference, but in no particular order):<br>
>         ><br>
>         ><br>
>         >         Thanks for doing this. We definitely need to be stepping back and<br>
>         >         thinking about this at a high level. I've attempted to step a little<br>
>         >         further back in my writeup:<br>
>         ><br>
>         >           <a href="https://wiki.openstack.org/wiki/Oslo/Messaging" target="_blank">https://wiki.openstack.org/wiki/Oslo/Messaging</a><br>
>         ><br>
>         >         > 1. Application code using RPC connections must not be required to know to<br>
>         >         > pass different arguments to establish the connection (i.e., the app<br>
>         >         > shouldn't have to care if it is using Rabbit or ZMQ).<br>
>         ><br>
>         ><br>
>         >         Yes.<br>
>         ><br>
>         >         > 2. An application must be able to direct a message to a specific peer<br>
>         >         > (i.e., call() with a host specified).<br>
>         ><br>
>         ><br>
>         >         s/direct a message to/invoke a method on/<br>
>         ><br>
>         ><br>
>         > RPC and notification aren't the only usage patterns for messaging. If<br>
>         > we're going to design a general purpose library, we should not limit<br>
>         > ourselves to RPC semantics. RPC can be built on top of messaging, but<br>
>         > it has been painful to try to make it work the other way around.<br>
><br>
><br>
>         I don't think the goal is to design a general purpose library, it's to<br>
>         clean up the APIs we already have to support our current usage patterns.<br>
>         The library can grow new APIs to support new usage patterns over time.<br>
><br>
>         I really don't want to design generic APIs in a vacuum when we have the<br>
>         much more pressing concern of our current usage patterns. I also don't<br>
>         want to unnecessarily restrict what messaging systems could be used to<br>
>         support our current patterns.<br>
><br>
><br>
> You've already, mostly, separated the transport stuff from the RPC<br>
> semantics. I think that's all I was asking for, but I want the way we<br>
> describe it to not say "invoke a method on" but just stick with<br>
> message delivery. The dispatcher for method invocation is one<br>
> server-side detail.<br>
<br>
</div></div>I think about it more in terms of the payload - I don't want users of<br>
the API ever to see this as "sending a message with 'method' and 'args'<br>
parameters'" ... it should be "invoke a method with the given name and<br>
args".<br></blockquote><div><br></div><div style>OK, I see that perspective.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
If we want to support messaging with alternative or free-form payloads,<br>
then we can do that later - right now, we don't have a use case for it.<br>
<div><div class="h5"><br>
>         >         But, yes.<br>
>         ><br>
>         >         > 3. An application must be able to direct a message to a pool of peers<br>
>         >         > (i.e., cast()).<br>
>         ><br>
>         ><br>
>         >         ... and for it to be delivered to one of those peers, yes.<br>
>         ><br>
>         >         > 4. An application must be able to direct a message to a specific peer (or<br>
>         >         > unknown? or both?) using a different rpc endpoint than the originating<br>
>         >         > app's default (i.e., calling into cells).<br>
>         ><br>
>         ><br>
>         >         I've tried to separate the notion of a transport from the target. The<br>
>         >         properties of the target is what's known to the application code, the<br>
>         >         properties of the transport are target specific and come from<br>
>         >         configuration.<br>
>         ><br>
>         >         So, I'd say "an application must be able to invoke a method on a<br>
>         >         specific target using a supplied transport configuration".<br>
>         ><br>
>         ><br>
>         > Something has to know how to map the target to the configuration. What<br>
>         > does that, and how much does that code know about the transport?<br>
><br>
><br>
>         Ok, on the client side:<br>
><br>
>           <a href="https://wiki.openstack.org/wiki/Oslo/Messaging#Client_Side_API" target="_blank">https://wiki.openstack.org/wiki/Oslo/Messaging#Client_Side_API</a><br>
><br>
>         for the simple case, you'd have something like:<br>
><br>
>           rpc_driver = rpc.get_transport_driver()<br>
><br>
>           base_rpcapi = BaseAPIClient(rpc_driver)<br>
><br>
>           base_rpcapi.ping(context, 'foo')<br>
><br>
>         for the more complex case, you'd have:<br>
><br>
>           class MeteringAPIClient(rpc.RPCClient):<br>
><br>
>               target = rpc.Target(exchange='ceilometer',<br>
>                                   topic='metering',<br>
>                                   version='1.0')<br>
><br>
>               def __init__(self, driver):<br>
>                   # FIXME: need some way to override with exchange from URL<br>
><br>
><br>
> Ceilometer knows which exchanges to listen on based on its plugins and<br>
> configuration (we know to look for the glance notification config<br>
> option when the glance-related plugins are activated, for example).<br>
<br>
</div></div>Right, and this is relevant to the notifications consumption API.<br>
<div class="im"><br>
> Cells will know because they will have some configuration setting(s)<br>
> per cell they want to talk to in the database.<br>
<br>
</div>Yes, and this is why I want to support it in the transport URL.<br></blockquote><div><br></div><div style>Right. What I'd like to do is move entirely to URLs, with a backwards-compatibility layer for getting the default URL from the config settings if there is no URL value set. So if the user sets rpc_broker_url, we use that by default. If they don't, we combine the values of the existing driver options to make a URL and then use that.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
> Are those the only cases we have now? Are they the only cases we<br>
> anticipate?<br>
<br>
</div>Well, we also have the control_exchange config varibale. So we need to<br>
default to control_exchange, but allow the transport driver URL to<br>
override it?<br>
<br>
The MeteringAPIClient example I had in mind above was the code for a<br>
Nova notifications plugin - the code runs in Nova, so control_exchange<br>
will be 'nova' but we know the default should be 'ceilometer' even if it<br>
gets overridden by the transport URL.<br></blockquote><div><br></div><div style>I thought the ceilometer notifier would instantiate its own RPCClient, using its own configuration option to set the transport stuff up. The plugin won't even look at nova's "global" settings for RPC.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
>           ---<br>
><br>
>           rpc_driver = rpc.get_transport_driver(url='kombu://broker//ceilometer')<br>
><br>
>           metering_rpcapi = MeteringAPIClient(rpc_driver)<br>
>           metering_rpc_api.record_metering_data(...)<br>
><br>
>         The annoying bit here is the application code should know what the<br>
>         default exchange is, but there is a use case for it to be overridden by<br>
>         configuration.<br>
><br>
><br>
> If the application gets the URL to pass to get_transport_driver() from<br>
> a config file or the database, does it even need to know there is such<br>
> a thing as an "exchange" any more?<br>
<br>
</div>It needs to know what the default is - i.e. Nova needs to set it to<br>
'nova' process-wide and Ceilometer's notification plugin needs it to be<br>
'ceilometer'<br></blockquote><div><br></div><div style>See above.</div><div style><br></div><div style>Doug</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<br>
Cheers,<br>
Mark.<br>
<br>
<br>
</blockquote></div><br></div></div>