I've been pecking a way at this online chat program that I started as an excuse to learn some JavaScript and enhance my PHP skills (as well as get around a certain corporate firewall). It's coming along nicely. Tonight I added a RSS feed for it so that users can monitor the most recent conversation without having to be constantly logged in. I've been trying to figure out a good way to manage the deployment of the web application.

My design philosophy in the last year or two has switched from "Big, Massive Projects That I Can Never Finish Given My Diminishing Spare Time" to "Small, Constantly Evolving But Always Fully Functional Projects". The paradigm shift was a result of simply not having enough time, energy, and enthusiasm to commit to a large project and constantly feeling the pain of never finishing what I started. Now, I can play with a project, add a few new features to it and put it away for some time. At all stages of "release", the project is fully functional, yet I've always got a laundry list of future features which I'll eventually get to. So far, it's led to a couple interesting little applications, the most complete of which is the afore-mentioned instant messaging web application.

Anyway, the Instant Messenger was unique in my experience so far because there were multiple users who, at any point and time, may be using the latest version of the application.

Deploying the new version into the same directory was not a good idea because the instant messaging application relied on asynchronous JavaScript calls to fetch conversation data that was uniquely identified. In short, adding in new features had the potential to break existing sessions.

Thus, I ended up developing and testing the newer version in a private web directory, then broadcasting to all participants: "Ok, I'm going to deploy the next version of the chat program so everybody log out for a couple minutes". I'd then scurry around in my website file manager, setting up some config files, rename some directories and then log back in and wait for the other participants to rejoin.

Not the best deployment plan, I know.

Tonight I struck on an easier way for me to deploy the application without having to force people to log off.

First, I set up the directory structure like this:

/chat/
/chat/1.0/
/chat/1.1/
/chat/1.2/
/chat/WIP/

All versions of the chat program code are located in subdirectories inside /chat/. The most recent "live" version in this example is located at /chat/1.2/. The 1.2 directory houses all the PHP, JavaScript, user information, conversation and state information for that version of the application. For instance, /chat/1.2 might contain:

/chat/1.2/index.php
/chat/1.2/some_scripts.js
/chat/1.2/serverside_stuff.php
/chat/1.2/rss.php
/chat/1.2/users.passwd
/chat/1.2/chat0000.xml
/chat/1.2/chat0001.xml
...

Similarly, the /chat/WIP/ folder is my "Work In Progress" folder that allows me to experiment freely without upsetting anyone.

Now it's kind of a hassle to ask people to browse to http://www.mydomain.com/chat/1.2/index.php and then when I update to 1.3, tell them they have to update their bookmarks accordingly to http://www.mydomain.com/chat/1.3/. Such a scheme would hardly be "user friendly" and it wouldn't scale properly to an application with a large user base. Same goes for the RSS link (http://www.mydomain.com/chat/1.2/rss.php).

So what I did was a simple PHP trick. I created the following files

/chat/
/chat/deploy.php
/chat/index.php
/chat/rss.php

/chat/1.0/
/chat/1.1/
/chat/1.2/
/chat/WIP/

The content of these files are as follows:

/chat/deploy.php:

<?php
    $DEPLOY_MYCHAT_CUR_VER = "1.2";
?>

/chat/index.php:

<?php
    include 'deploy.php';
    $urlstr = "http://www.mydomain.com/chat/" . $DEPLOY_MYCHAT_CUR_VER . "/index.php";
?>
<html><head>
    <meta HTTP-EQUIV="Refresh" content="0; URL=<?php echo $urlstr; ?>" >
</head><body/></html>

/chat/rss.php:

<?php
    include 'deployment.php';
    $filestr = "./" . $DEPLOY_MYCHAT_CUR_VER . "rss.php";
    include $filestr;
?>

Now what's the benefit of this? Well, if a user browses to http://www.mydomain.com/chat/ they will end up at http://www.mydomain.com/chat/1.2/index.php. i.e. the most recently released version of the application and all their doings-and-goings-on will be isolated to the /chat/1.2/ folder.

Meanwhile, I finally finished up feature XYZ in the WIP and want to deploy the new version. What do I do?

I create a /chat/1.3/ folder and copy the contents of the WIP into it. Then I modify /chat/deploy.php such that $DEPLOY_MYCHAT_CUR_VER equals "1.3".

Now anyone currently logged into the chat program can safely stay on 1.2 for as long as they want. However, the moment they log out, when they try to log back in, they will automatically end up at http://www.mydomain.com/chat/1.3/. What I like about this is: 1) there is no requirement for any user currently using the application to log out; they are safe in their "1.2" buckets and 2) there is no requirement for me to rename existing folders, mess with configuration files, etc. Deployment is a simple two-step process.

To end this entry, I'll discuss a third thing I like about this technique. I could centralize the data (i.e. the conversations, the user information such as passwords) into the /chat/ directory and allow any version to access this common data. This means that someone using version 1.2 would be able to chat with someone using version 1.3. As long as the backing data store is in a format that easily downgrades for older versions (i.e. XML elements/attributes or database tables/fields that would simply be ignored by older "less-smart" versions). Of course doing so might require some type of synchronization across deployment versions and may end up causing me another deployment nightmare all over again.

§96 · May 24, 2005 · Ajax, JavaScript, PHP, Software, Technology, Tips, Web · · [Print]

Leave a Comment to “Deploying For The Live Web”

  1. Rob says:

    Well it sounds like you’ve definitely cleared one hurdle for scalability. I think that scheme would work for a lot of shared-user ajax applications. Mind if I shamelessly copy?

  2. If I wanted to keep this private, I wouldn’t have blogged it. But I guess “acknowledgments” would be preferred over “shamelessly copy” 😛