January 15, 2009
Spawning 0.8.8 released
Another minor Spawning release cleans up some log messages, the way PYTHONPATH and the location of python are determined, and adds some convenient command-line options for controlling the operation of the server. Here are the release notes:
- Added --access-log-file command line option to allow writing access logs to someplace other than stdout. Useful for redirecting to /dev/null for speed
- Correctly extract the child's exit code and clean up the logging of child exit events.
- Add coverage gathering using figleaf if the --coverage command line option is given. When gathering coverage, the figleaf report can be downloaded from the /_coverage url.
- Add a --max-memory option to limit the total amount of memory spawning will use. If this is exceeded a SIGHUP will be sent to the controller causing the children to restart.
- Add a --max-age option to limit the total amount of time a spawning child is allowed to run. After the time limit is exceeded a SIGHUP will be sent to the controller to cause the children to restart.
- Instead of just passing the PYTHONPATH environment variable through to the children, construct the PYTHONPATH from the contents of sys.path.
- Instead of just trying to run 'spawn' with /usr/bin/env when restarting, just run sys.executable -m spawning.spawning_controller, making it more likely that the controller will run correctly when restarting.
- Add a --verbose option and change the default startup procedure to not log the detailed dictionary of configuration information.
Posted by Donovan at 2:11 PM | Comments (0)
January 14, 2009
Python binding for Mongrel's http11 parser
Last weekend I wrote a Python binding for Mongrel's http11 parser. I will probably integrate this into eventlet.wsgi and Spawning at some point, but it's not really that much faster than eventlet.wsgi's existing pure python http parser, so I'm not in a hurry.
I decided to release the code on github in case anybody else is interested in playing around with it in the meantime. This is the first time I've used git to commit and push. So far my impression of git compared to darcs and hg is very good. git seems easy enough to use and is very fast. There's not a compelling reason to use it over hg except for the fact that pretty much everybody else in the world seems to be leaning towards git.
Posted by Donovan at 2:57 PM | Comments (0)
December 19, 2008
Evolution of Codependency in Antagonistic Relationships
I'm reading Out of Control: The New Biology of Machines, Social Systems, & the Economic World, a most excellent book about complexity. This quote caught my eye:
In defending itself so thoroughly against the monarch, the milkweed became inseparable from the butterfly. And vice versa. Any long-term antagonistic relationship seemed to harbor this kind of codependency. (p 74)
This made me realize something about the nature of governments and war: Governments evolved to protect resources and people from the threat of outside invasion. An organizing structure was required to create and maintain a fighting force capable of resisting invasion from neighbors. However, it's now obvious that governments are in a codependent relationship with war: If there were no more war, then there would be no need for a government's ability to organize a fighting force. Therefore it's in a government's best interest to ensure that war never ceases.
However, just like any other codependent relationship, a lot of denial takes place. I doubt most politicians would come out and say that a prime function of government is to create war. Actions speak louder than words, though, and it's clear that in the thousands of years of human civilization there have been plenty of wars.
Posted by Donovan at 9:40 PM | Comments (2)
lxml + eventlet mashup
Since Ian was kind enough to give me instructions that gave me a working lxml (I had never been able to compile it before), I thought I'd write a quick scraper by mashing lxml together with eventlet.
The result is a thing of beauty:
from os import path
import sys
from eventlet import coros
from eventlet import httpc
from eventlet import util
from lxml import html
## Make httpc work -- I'll make it work without this soon
util.wrap_socket_with_coroutine_socket()
def get(linknum, url):
print "[%s] downloading %s" % (linknum, url)
file(path.basename(url), 'wb').write(httpc.get(url))
def scrape(url):
root = html.parse(url).getroot()
pool = coros.CoroutinePool(max_size=8)
linknum = 0
for link in root.cssselect('a'):
url = link.get('href', '')
if url.endswith('.mp3'):
linknum += 1
pool.execute(get, linknum, url)
pool.wait_all()
if __name__ == '__main__':
if len(sys.argv) == 2:
scrape(sys.argv[1])
else:
print "usage: %s url" % (sys.argv[0], )
This script manages to max out my bandwidth -- 800KB/sec at home and 2.5MB/sec at work -- without breaking a sweat. It oscillates between about 10% and 20% CPU on my MacBook Pro. Nice!
Posted by Donovan at 9:14 PM | Comments (1)
December 7, 2008
ptth (Reverse HTTP) implementation in a browser using Long Poll COMET
ptth is an idea I have planning on implementing for a few years now. The basic idea is that you take normal HTTP semantics and reverse them, meaning that the client (from the TCP perspective) acts like a server (from the application perspective), and the server (from the TCP perspective) acts like a client (from the application perspective) and makes requests on the client whenever it feels like it. This is distinguished from most normal COMET semantics in that ptth retains all of http's characteristics even though the underlying transport is radically different looking at the TCP level.
When I was at Linden Lab, I advocated using this technique in the Second Life Viewer as a refinement of the Plain Old COMET implementation currently in use (which I also helped implement). I wrote a wiki page describing how the http Upgrade: header can be used to initiate a ptth connection, effectively turning a socket that the client opened to the server around, allowing the server to make requests on the client as if the server had opened a connection to the client (even though it didn't). I even did an implementation in Python showing how once the Upgrade: has been performed the semantics are exactly the same as normal http. This means with a little hackery it's possible (and in the Python case, almost trivial) to reuse existing http client and server libraries. All you have to mess around with is the setup of the socket; once both sides have an open socket and have agreed to Upgrade:, you just grab the underlying socket and pass it to the client or server library and away you go.
Even though I didn't get the chance to implement and deploy this technique in the Second Life Viewer and Server before I left Linden for Mochi, I still hope this gets implemented someday, as I think it is a very elegant and efficient technique. While implementing the real ptth Upgrade: in C++ will be more challenging than doing a quick Python prototype, once the dirty business of extracting sockets and injecting them into the client and server libraries used is complete, it should be a very reliable technique since at that point everything is exactly the same as normal http.
However, it won't be possible to do these type of Upgrade: shenanigans when we are in the browser's Javascript environment and don't have access to low level details like socket APIs. Therefore, I also specced out what ptth would look like running over a Plain Old COMET Long Poll style transport. The wiki page describes encoding the reverse request and response as JSON for ease of parsing and generating in Javascript, but other content-types could be used (application/x-http-request and application/x-http-response perhaps, or maybe the message/http mime type could simply be used or modified to be message/http+request and message/http+response?)
On Saturday the 6th we had a Mochi Hack Day at our office, and I was hacking on my perpetual hacking project, Pavel. If you don't know me personally and haven't heard me talk about Pavel, someday I'll flesh out the ideas behind it more fully in a series of web pages, but for now you can read this old blog post to get a rough idea of what it is. The post uses the term "graphical multiuser networked programming environment" to describe the basic idea. From the very beginning I conceived ptth as a vehicle for driving updates of the user interface to Pavel, so I decided to get down to it and actually implement it. Since I have implemented so many COMET servers at this point that I have lost count, it turned out to be almost trivially easy, and I had something working in a few hours.
And now the part everyone has been waiting for: the demo. The demo takes place in firebug, where you can see the Javascript side of the Long Poll operating, and in the eventlet backdoor running inside of a terminal. The eventlet backdoor gives me a Python interactive REPL into the process which is serving the server side of the Long Poll, and allows me to manually inject ptth messages into the system which then get delivered to the browser, which then responds to the request. The first thing you see me doing is building a simple ptth request by hand, encoded in JSON. I then inject this message into the ptth system, copying and pasting the uuid of the user who is connected via the Firefox browser in the background. You can see the debug printing in Firebug showing that the request was delivered to the browser, and the result in the backdoor's REPL is the response that was generated in Javascript and sent back to the server.
This means that I now need to implement some sort of web framework in Javascript. I know Dojo has already done this and I'm sure other people will start to experiment with this idea as well, but for my purposes I'll probably come up with something super simple. The idea that immediately came to my mind is to have URIs represent XPath into the html document, and PUT replacing the selected node with the content fragment from the request body of the PUT.
Posted by Donovan at 3:09 AM | Comments (2) | TrackBacks (0)