<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Apr 29, 2013 at 11:25 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:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="im">On Mon, 2013-04-29 at 10:43 -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>
><br>
> A few comments/questions on that:<br>
<br>
</div>All good questions, thanks Doug.<br>
<div class="im"><br>
> In the client, it seems like the rpc.Target() should be passed to the<br>
> RPCClient constructor, rather than specified as a class attribute.<br>
<br>
</div>I was seeing the class attribute as being the defaults for method<br>
invocations ... to make those defaults be per instance, you could do<br>
something like:<br>
<br>
  class BaseAPIClient(rpc.RPCClient):<br>
<br>
      def __init__(self, driver,<br>
                   topic='blaa', version='1.0', namespace='baseapi'):<br>
          self.target = rpc.Target(topic=topic,<br>
                                   version=version,<br>
                                   namespace=namespace)<br>
<br>
... but maybe the point here is that we never expect this class to be<br>
used with a different topic, version or namespace.<br></blockquote><div><br></div><div style>Right, I see all of those settings as part of defining where the messages sent by the client should be going. I like the idea of encapsulating them in a Topic which is either passed to the base class or a required property (if BaseAPIClient is an abstract base class, for example).</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class="im"><br>
>  The target parameters should include the host (or "peer" to use<br>
> Eric's terminology), shouldn't it?<br>
<br>
</div>Yes, absolutely:<br>
<br>
      def get_backdoor_port(self, context, host):<br>
          self.call(self.target(version='1.1', host=host),<br>
                    'get_backdoor_port', context)<br>
<br>
The host would be added to the default target parameters at method<br>
invocation time.<br></blockquote><div><br></div><div style>Ah, no, that's not what I meant. I meant that the host should be specified when the client is constructed. Maybe that makes it too inconvenient to use given our existing patterns?</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
Note, though, this is about a client specifying one of a pool of<br>
listening servers ... it's certainly not a peer of a client, and we're<br>
not talking about peers at the transport level either.<br></blockquote><div><br></div><div style>Yeah, we still need to figure out what to call that. "Server" is heavily overloaded, so Eric suggested "peer" as the name of the remote thing we're talking to.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class="im"><br>
> On the server side, I like separating the dispatcher from the server,<br>
> but I wonder if the server needs to know about the dispatcher at all?<br>
> Why not just give the server a single callable, which might be a<br>
> Dispatcher instance? It isn't clear why the dispatcher has start() and<br>
> stop() methods, either, but maybe that has something to do with this<br>
> design.<br>
<br>
</div>Yeah, exactly.<br>
<br>
In BlockingDispatcher, start() would read messages and dispatch them to<br>
the API objects we have listening on this topic and stop() would cause<br>
that dispatch loop to exit.<br>
<br>
In EventletDispatch, start() would spawn off a greenthread to do the<br>
dispatching and stop() would cancel the thread.<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
That said, this part of the proposal doesn't feel very solid yet.<br></blockquote><div><br></div><div><div><br class="">Listening in a loop feels like a responsibility of the Service, not the dispatcher. The Dispatcher is both routing messages and (potentially) starting tasks now. Would it be cleaner to add another class that knows how to start and stop tasks, and let the dispatcher just use that? It would avoid permutations like EventletRPCDispatcher and EventletNotificationDispatcher. We would just have an RPCDispatcher that knows how to look up a method from a message and a NotificationDispatcher that looks up a method from a notification event type. They would both use an EventletTaskManager, BlockingTaskManager, or even implementations based on threads or multiprocessing.</div>
<div><br></div><div style>I don't see anything in the current dispatcher that looks like it is starting an eventlet task, though. Is that happening somewhere else, or do the individual methods deal with it themselves?</div>
<div style><br></div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="im"><br>
> In web frameworks the decorator for exposing a method is usually named<br>
> something like "expose" so how about rpc.expose instead of rpc.method?<br>
<br>
</div>Sounds good, updated.<br>
<div class="im"><br>
> Is fake_rabbit used for testing? If so, that transport should be its<br>
> own driver.<br>
<br>
</div>From a quick grep, it looks like it just enables the in-memory RabbitMQ<br>
transport. Maybe it should just be a parameter to the kombu transport<br>
driver.<br></blockquote><div><br></div><div style>That makes sense.</div><div style><br></div><div style>Doug</div><div style><br></div></div></div></div>