February 03, 2004

Continuation based web servers

I recently have been experimenting with writing simple applications in continuation based web servers. Continuations are a type of variable in Scheme that stores the state of a thread. They are good match for web servers, since you can use them to write a web application framework in which you can write a web application in a similar way to a normal program. I first read about continuation-based web servers in Paul Graham's article on Building Web Applications in Lisp. Paul Graham's a good salesman. He made it sound very alluring. I had to try it.

So, over the past few months, I have written a version of my personal page in two continuation based web frameworks - Seaside and PLT Scheme.

Seaside runs in Squeak Smalltalk. This is it's whole separate world, which is both good and bad. The good is that a database isn't really needed, you just use Squeak's memory to store everything, and save or load the whole Squeak environment as needed. The bad is that you have to do everything in this environment. No emacs! And you have to use an ugly, confusing GUI that has no relationship to the platform you are running in. And how would one telnet in and edit code? Yuck. But Seaside is a very nice framework. It allows you to embed the results of actions as blocks very naturally right where the controls are. For example a simple counter with plus and minus buttons:

renderContentOn: html
    html heading: count.
    html anchorWithAction: [self increment] text: '++'.
    html space.
    html anchorWithAction: [self decrement] text: '--'.

This makes writing pages very easy. There are problems, though. First of all, the server redirects you to the page with a session parameter. This is extremely ugly. So, if go to: "http://my.site/seaside/links" I get redirected to "http://my.site/seaside/links/@pcAAIJptPXWALgmy/LNsfQyMJ". So a visiting user has to bookmark this ugly URL that encodes a continuation session that almost certainly won't exist by the time the user returns. That's not good. Someone else raised the same point in the Seaside mailing list, and the poorly-thought out answer was "just store all session permanently in memory". That solution isn't very scalable, I'm afraid. The problem is it's hard to write an app that doesn't use sessions in this framework. Stateless communication is the natural state of the web, and therefore what the web does best. Seaside is an interesting framework, very easy to program in, but it needs to be able to do stateless page serving before I could really recommend it.

I also tested out PLT Scheme. According to blogger Bill Clementson, PLT Scheme is the best open source Lisp out. It comes with a continuation based web server. The framework is not really like Seaside. You can't embed actions in the page like you could in Seaside. Instead, you have to handle the responses all at once. The above example would be written something (I haven't tested or even made sure the syntax is correct) like:

(let ([count 0])
  (unit/sig () (import servlet^)
    (let loop ((count count))
         (let ((env (request-bindings 
                     (send/suspend
                      (lambda (k-url)
                        `(html (head (title "Counter"))
                               (body ([bgcolor "white"])
                                     (h1 ,count)
                                     (form ([action ,k-url [method "post"])
                                            (input ([type "submit"] [name "submit"] [value "+"]))
                                            (input ([type "submit"] [name "submit"] [value "-"])))))))))))
           (if (equal? (extract-binding/single 'submit env) "+")
               (loop (+ count 1))
             (loop (- count 1)))))))

A lot more unweildy, to be sure. Macros can help, and I'm thinking of ways to use them in a sensible manner. However, you can don't have to use the continuation-based sessions if you don't want to. I wrote my personal page in PLT Scheme, and didn't use sessions for the user-visible part. There was no point in it, since the interactions were not complex, and I wanted everything bookmarkable. But for my administartion page, it completely uses continuations, and I think the program is better for it. The only issue is that sessions time out, so if I start an administration task, then go and eat lunch, I'll have to restart from the beginning.

For my needs, I like PLT Scheme best, and I think my needs are not different from the normal web programmer's needs. Of course, for high-volume commercial sites, I wouldn't necessarily recommend it until it is a little more hardened. There have been reports of memory leaks. I'd like to make my new PLT Scheme-based personal page available, now I just have to figure out how to do this, since I can't exactly run it on my machine I pay for hosting on.

Posted by ahyatt at February 3, 2004 07:59 AM
Comments

>I'd like to make my new PLT Scheme-based
> personal page available, now I just have to
> figure out how to do this, since I can't
> exactly run it on my machine I pay for hosting on.

You could register a local machine on homedns.org, then link to it from your hosted site.

Posted by: wayne on February 13, 2004 07:03 AM

Not sure quite what you mean by the line "You can't embed actions in the page like you could in Seaside. Instead, you have to handle the responses all at once." but I have something that may help (click on my name for the link).

It's an inversion of the send/suspend control flow, so that you attach functions directly to links in your page. It eliminates the need for your "(if (equal? (extract-binding/single 'submit env) "+")" step.

Posted by: Pete Hopkins on February 19, 2004 02:49 PM

Nice! I was indeed looking for something like what you provided.

Posted by: Andrew Hyatt on February 19, 2004 04:42 PM

Check this out:

http://trac.cherrypy.org/wiki/CherryFlow

Continuation-based programming for CherryPy.

Posted by: Peter Hunt on January 21, 2005 12:37 PM
Post a comment














To post a comment, please type in the number of hours in a day (this is to help protect this site from spam by ensuring you are a human):