On 01/14/2015 01:28 PM, Rafael Schloming wrote:
Hi Everyone,

I've been doing some work on a C reactor API for proton that is intended
to fit both alongside and underneath what gordon has been doing in pure
python. I have several goals with this work.

  - Simplify/enable a reactive style of programming in C that is similar
to what gordon has built out in pure python.

  - Provide a C API that translates well into the python/ruby/etc
bindings, so that sophisticated handlers can be written once in C rather
than being duplicated in each scripting language.

  - Preserve the extensibility/flexibility that comes with being able to
define custom handlers in the bindings, so python/ruby/etc handlers can
intermix well with C handlers.

  - Provide a C API that translates well into javascript via emscripten.
In some ways this is similar to the above goals with the other language
bindings, however I mention it separately because there are additional
memory management constraints for javascript since it has no finalizers.

I believe I've made significant progress towards most of these goals,
although there is still plenty of work left to do. I'd like to share a
few examples both to illustrate where I am with this and to solicit
feedback and/or help.

Let me say up front that these examples aren't intended to be "hello
world" type examples. The focus of this work has really been on the
reactor/handler/event-dispatch infrastructure, and so the example I've
chosen is really intended to illustrate key aspects of how this works.
To do that I've built an example that sets up a recurring task, a
server, and a client, all within the same process and then sends a
number of messages to itself.

I've included the same example twice, once written in C and once written
in the python binding of the C API. Please have a look and let me know
what you think.

Attached is that example using the pure python utilities I've been working on. It's similar in many ways, but there are some differences.

Ideally we can start to reconcile these differences, particularly for the python bindings, both to avoid the confusion of having slightly different variants of the same functionality and to allow more flexible combining between c and python (e.g. calling c handlers from python, using the c event loop with python handlers etc). I think that exercise will also be a useful way of solidifying some of the interfaces.

There are a couple of immediate improvements I want to make based on your example. The first is having the 'reactor' (I currently call the equivalent 'container') as a property of all events. That avoids the need to explicitly 'plumb it in' to components. The other is to add a handler argument to the schedule call allowing specific timed events to be handled by a given piece of logic.

The second point also opens up the wider question of how handler scoping works. There are some differences there between our approaches that are worth digging into and rationalising.

The first point impacts on a question I've been thinking about which is the correct layering (if any). I started to use the term 'container' for something that had some higher level utility as an AMQP container, over and above the 'event loop'. Figuring out what the layers are, what they should be called and what exactly their interfaces are will be worthwhile.

Anyway, more to come on all this from me, but I wanted to chip in briefly. I think we are building some momentum around the approach here, the c variant is an interesting addition - nice work - and I think also an opportunity to start unifying and consolidating things.

#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

from proton import Message
from proton.handlers import MessagingHandler
from proton.reactors import Container
import sys
import time

class Printer(MessagingHandler):

    def __init__(self):
        super(Printer, self).__init__()
        self.count = 0

    def on_message(self, event):
        self.count += 1
        print "RCVD[%s]" % self.count, event.message

class PeriodicThingy:

    def on_start(self, event):
        print "scheduling", time.ctime(time.time())
        self.container = event.container
        self.container.schedule(0)

    def on_timer(self, event):
        print "Hey", time.ctime(time.time())
        self.container.schedule(time.time() + 1)

class Client(MessagingHandler):

    def __init__(self, container, messages):
        super(Client, self).__init__()
        self.container = container
        self.messages = messages

    def on_connection_opened(self, event):
        self.container.create_sender(event.connection, "")

    def on_credit(self, event):
        snd = event.sender
        while snd.credit > 0 and self.messages:
            snd.send_msg(Message(body=self.messages.pop()))

container = Container(Printer(), PeriodicThingy())
container.listen("localhost:5672")
container.connect("localhost:5672", handler=Client(container, sys.argv[1:]))
container.run()

Reply via email to