Fork me on GitHub

Posts tagged mongrel2

Y U NO USE WSGI?

BRUBECK CAN NOW

class DemoHandler(WebMessageHandler):
    def get(self):
        name = self.get_argument('name', 'dude')
        self.set_body('Take five, %s!' % name)
        return self.render()

config = {
    'msg_conn': WSGIConnection(),
    'handler_tuples': [(r'^/brubeck', DemoHandler)],
}

app = Brubeck(**config)
app.run()

NO MONGREL2

$ ./demo_wsgi.py 
INFO:root:Using coroutine library: gevent
Brubeck v0.3.9 online ]-----------------------------------
Serving on port 6767...

That’s it. You’re running. It’s using either gevent.wsgi or eventlet.wsgi so all the non-blocking goodness is still all there.

Y U NO USE MONGREL2?!

HELP

Thanks to Thomas Ballinger and Steven Ciraolo for writing most of the code. I can’t wait to see what they’re up to next.

TRYING IT

The latest work is in the wsgi_support branch. There is a demo_wsgi.py, which doesn’t require Mongrel2 or ZeroMQ and, by default, starts on port 6767.

I will probably move it into master after we’ve done some more testing on it.

ON WSGI

I must admit, I am a little bummed to include WSGI support when I believe Mongrel2 is the rightest way to do web serving, but I am happy to open Brubeck itself up to more people. I also hope they will give Mongrel2 consideration when deploying Brubeck in production environments.

On the other hand, I am happy to include another point that Brubeck is aware of, yet agnostic towards. If you have a different opinion on the web server from me, well, I guess we can accomodate that. It’s 50 lines of Python, in the new design, so whatever… I’m in!

It will surely be fun to compare WSGI vs ZMQ, now that we have something of a control on the rest of the framework. SCIENCE.

Edit: @jiaaro has pointed out that the wsgi_support still requires zmq to be installed by nature of how the imports work. Drat, I didn’t think of that. I will fix that before this branch is merged into master.

See more
Tagged with code, brubeck, wsgi, zeromq, mongrel2,
Posted at 9:56 AM 18 April 2012

Mongrel2, a short introduction

Please take a look at those slides. They’ll give you the gist of Mongrel2’s design and I’ll elaborate on them below. Notice that the slides start by speaking about Mongrel, which is Mongrel2’s predecessor. It is fundamentally different from Mongrel2, but it does share some things, like the HTTP parser, in common.

These slides are by Paolo Negri.

Some thoughts on Mongrel2

I am somewhat enamored by Mongrel2 lately. It’s design is simple and focused, yet the server does everything you need.

Mongrel2 is the web server. So your browser, a phone or any app might go to yoursite.com and communicate with a Mongrel2 instance. Mongrel2, however, might communicate with something else to fulfill the request. By nature of using a message passing system, it becomes asynchronous and decoupled from how the work is actually being done. Something big sites all scale into eventually anyway.

By using the ZeroMQ framework for it’s message passing it also gains language independence. I could have a Python process sharing load with a Java process alongside some Lua. Any language that supports ZeroMQ can work. Mongrel2 just does web serving and leaves the rest up to you, via configuration.

ZeroMQ currently supports many lanugages

It gets better too. ZeroMQ is an extensive framework all in itself. You can open a connection to a computer that doesn’t exist and start sending messages. It will queue them up and wait for when that system comes online. You could have it simply error if you think that’s appropriate.

One of my favorite things to do is turn on Mongrel2, request a URL from my browser, then turn on one of my Python request handlers. After it’s initialized, it reads the message and responds. Mongrel2 sends the response to my browser. ZeroMQ absorbed the down handler until it was ready.

It gets a little better, still. So now I’ll open a second request handler, to pretend I’m scaling up to handle load. Mongrel2, with no config change or restart, immediately starts sending messages round-robin to each handler instance!

Request handling

Mongrel2 is configured by mapping three types of request methods: Dir, Proxy, Handler. You configure URL routes to each of these, depending on your needs. The configuration looks like below.

# here's a sample directory 
media_directory = Dir(base='media/', 
                      index_file='index.html', 
                      default_ctype='text/plain') 
 
# a sample proxy route 
tornado_proxy = Proxy(addr='127.0.0.1', port=8000) 
 
# a sample zeromq handler 
chat_demo = Handler(send_spec='ipc://127.0.0.1:9999', 
                    send_ident='54c6755b-9628-40a4-9a2d-cc82a816345e', 
                    recv_spec='ipc://127.0.0.1:9998', recv_ident='')

Three types of request

If it’s a static file request M2 uses Dir handling. It reads the path and expects to find a static file there or follows some common web handling conventions, such as loading index.html. Useful for hosting media.

Proxy handling is similar to the upstream concept from Nginx. You can simply pass the request and it’s details up to something else, like Tornado or Django, for handling the request.

The Handler type is where Mongrel2 really shows it’s power. This type sends the request down a socket for handling and waits to receive responses on another socket. Communication can happen in both directions using different semantics. The handler can exist basically anywhere. It might consume a local socket, like you see configured above with the ipc socket, or it might use a tcp socket to connect to a remote system. It’s configurable and flexible.

Existing handlers

There have been a few interesting ideas for how to handle Mongrel2 sockets. You can build a handler using whatever language inspires you.

Zed wrote a framework in Lua called Tir.

For PHP there is Photon or m2php.

Some folks have written a WSGI interface to Mongrel2 messages. This lets a user run a Django instance and turn on another Django instance, to scale up, without ever bouncing the web server.

As you might know, I built MongrEvent as an example of one way to build a handler in Python. I’ve got a more robust one on the way, modeled loosely after Tornado and Bottle.

This project is Brubeck. I’ve used that name for projects in the past, but this project feels most deserving.

Digression: I’ll have to find a way to revive the Dillinger name at some point too… It’s being wasted on my experiment merging Tornado and ZeroMQ from before I got into Mongrel2.

See more
This post has 3 notes
Tagged with mongrel2, code, zeromq,
Posted at 1:25 PM 09 February 2011

MongrEvent at Hack and Tell

I will be speaking at Hack and Tell tomorrow night. I am presenting MongrEvent and discussing some thoughts on using a pipeline of coroutines for answering zeromq messages.

It’s currently focused on answering messages from Mongrel2, but I’m starting to think something bigger could be really neat. I even have a name ready.

The meetup starts at 6:30pm. See website for more info.

See more
Posted at 9:52 PM 06 February 2011

MongrEvent

MongrEvent is a proof-of-concept for writing a Mongrel2 message handler in Python and splitting the processing into a pipeline of coroutines.

Mongrel2 is a web server by Zed Shaw. Mongrel2 handles everything having to do with HTTP and has facilities for passing request handling to external services using ZeroMQ. MongrEvent is an example of how that service could be written to use Eventlet for coroutines. We also get non-blocking I/O very cheaply.

The Mongrel2 handling code is based on Zed’s python in mongrel2’s source.

Code

The code is on github: https://github.com/j2labs/mongrevent.

The Design

Mongrel2 is configured to only answer on /echo/, or http://localhost:6767/echo/. Mongrel2 receives the reqeuest and forwards it down tcp://127.0.0.1:9999, where handling.py is listening. This socket is a ZeroMQ PUSH socket.

Read about the different socket types ZeroMQ offers in the manual.

When handling.py is initialized, it sets up an input and output zmq socket for mongrel2. It’s my personal preference to remember input and output instead of PUSH and PUB (publish), the actual zeromq socket types used.

A coroutine is started to handle each request. The assumption is that a routing system could live in this coroutine. Once a route is determined, a subsequent coroutine is created to handle the request. A third coroutine is then created to handle the result of that request, like a postprocessing system.

The third coroutine responds to Mongrel2 by sending it’s response on handling.py’s PUB socket. Mongrel2 picks up the message and then responds, completing the request.

Mongrel2

If you’re new to Mongrel2, you should read Zed’s documentation on mongrel2.org. The rest of this doc assumes you’ve installed it successfully.

Mongrel2 Config

The gist of it is that we have one host that answers to /echo/. Requests to /echo/ are configured to go to our handler by way of tcp://127.0.0.1:9999. It is also listening on tcp://127.0.0.1:9998 to receive answers for our handler.

echo_handler = Handler(
    send_spec='tcp://127.0.0.1:9999',
    send_ident='34f9ceee-cd52-4b7f-b197-88bf2f0ec378',
    recv_spec='tcp://127.0.0.1:9998', 
    recv_ident='')

j2_host = Host(
    name="localhost", 
    routes={'/echo/': echo_handler})

j2_serv = Server(
    uuid="f400bf85-4538-4f7a-8908-67e313d515c2",
    access_log="/logs/access.log",
    error_log="/logs/error.log",
    chroot="./",
    default_host="localhost",
    name="j2 test",
    pid_file="/pids/mongrel2.pid",
    port=6767,
    hosts = [j2_host])

settings = {"zeromq.threads": 1}

servers = [j2_serv]

Running it

Load the config and start mongrel2 up. It doesn’t matter that we don’t have a handler up yet.

$ m2sh load --config env/j2.conf --db j2.db
$ m2sh start -db j2.db -host localhost

You should see mongrel2 register a PUSH socket and a SUB socket as it’s last lines of output.

Python

I have stored the essential parts of my Python environment in a requirements file. I was not able to install pyzmq with pip and have it honor zeromq being installed in /opt/local so I install that separately.

$ mkvirtualenv mongrevent
(mongrevent) $ pip install -I -r ./requirements.txt

Now for pyzmq. This requires zeromq, so if please install if necessary.

(mongrevent) $ cd ~/Desktop/
(mongrevent) $ git clone git://github.com/zeromq/pyzmq.git
(mongrevent) $ git checkout v2.0.10
(mongrevent) $ # cp setup.cfg.template to setup.cfg and edit if necessary
(mongrevent) $ python ./setup.py install

Assuming that worked, you should be able to turn on handling.py.

(mongrevent) $ ./handling.py
System online ]-----------------------------------

Testing it

Just load up http://localhost:6767/echo/ with curl and see how it responds. You should see the same as below.

$ curl "localhost:6767/echo/"
/ohce/
See more
Posted at 6:16 PM 02 February 2011