More code! Login…

In our last post, we designed the login process.  This post will actually walk through the implementation.  It assumes you have followed the steps in the post where we created the application’s skeleton and did the initial database migration steps so make sure you are starting from there.  Also, please note that at the time this is being written, node.js is on version 0.8.11 so if this is a long time ago to you future travelers down this path, your mileage may vary. Login Screen: So our first step is to actually have a screen that gets rendered when someone navigates to the /login route.  To do this in Node using Express is pretty straightforward.  First, you need to create a view in the “views” subdirectory called login.jade (example below).  If you aren’t familiar with the Jade templating technology, take a look at it’s home site.

extends layout

block content
  form(action='/login', method='post')#login-form
    h1= title
    p You need to log in
    label Email
    input(name='user[email]')
    <br />
    label Password
    input(name='user[password]', type='password')
    <br />
    button(type='submit') Sign in

Next, we’ll need to add a file in the routes subdirectory called “login.js” to handle the rendering of a GET call to the /login route:

exports.index = function(req, res) {
  res.render('login', { title: 'Login' });
};

With that done, we can now connect our route in app.js and test it:

...
var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , login = require('./routes/login')
...

...
app.get('/', routes.index);
app.get('/login', login.index);
...

Test it out by firing up the server from the command line (node app.js) and hitting localhost:3000/login from your browser.  You should see a simple (and very unattractive) login page. Now we need to write some middleware to catch all http calls to the application and redirect them to this login page if they don’t have our session cookies.  To do that, we’ll add some code to the top of app.js:

function sessionMiddleware(req, res, next) {
  if (req.url == '/login') {
    next();
  } else {
    if (req.cookies.user == undefined) {
      res.redirect('/login');
    } else if (req.cookies.session == undefined) {
      res.redirect('/login');
    } else {
      next();
    }
  }
}
...

...
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(sessionMiddleware);
app.use(app.router);
...

Also add the cookieParser() and sessionMiddleware lines near the bottom. Now if you stop and restart your command-line and hit the site again, you’ll find that if you go to http://localhost:3000/ (or any other route for that matter), you will end up at the /login page. So now we need to do one last thing.  Add code to actually capture the information entered on the login form, compare it to what we have in the database and set the necessary cookies to allow access to pages in the site.  First things first, install a new npm module called ‘node-uuid’:

npm install node-uuid

Next, let’s add a migration to put a column called session_id on the users table:

db-migrate create add-session-id

...

var dbm = require('db-migrate');
var type = dbm.dataType;

exports.up = function(db, callback) {
  db.addColumn('users', 'session_id', 'string', callback);
};

exports.down = function(db, callback) {
  db.removeColumn('users', 'session_id', callback);
};

...

db-migrate up

Now, let’s create the code to deal with the POST on the login page.  Modify the routes/login.js file to include a new method at the top of the file:

var crypto = require('crypto');
var uuid = require('node-uuid');

var pg = require('pg');
var connectionString = 
  'tcp://hrtool:password123%25@localhost/hrtool_dev';

exports.login = function(req, res) {
  pg.connect(connectionString, function(err, client) {
    shasum = crypto.createHash('sha1');

    client.query('SELECT password from users where name=$1',
      [req.body.user.email], function(err, result) {

      hashedPassword = 
        shasum.update(req.body.user.password).digest('base64');

      if (result == undefined || result.rows.length != 1) {
        res.clearCookie('user');
        res.clearCookie('session');
        res.redirect('/login');
        return;
      }

      if (result.rows[0].password == hashedPassword) {
        sessionID = uuid.v1();
        client.query('update users set session_id=$1 where ' +
          'name=$2', [sessionID, req.body.user.email], 
          function(err, result) {
        });

        res.cookie('user', req.body.user.email);
        res.cookie('session', sessionID);
        res.redirect('/');
      } else {
        res.clearCookie('user');
        res.clearCookie('session');
        res.redirect('/login');
      }
    });
  });
}

Notice that we have to encode the ‘password123%’ password we chose to access PostgreSQL as ‘password123%25’ so that the percent sign is properly escaped in the connection string.  We now have to add the route to the bottom of the app.js file:

...
app.get('/login', login.index);
app.post('/login', login.login);
...

If we re-launch the application at the command-line, login should be working using our ‘admin’, ‘password123%’ userid and password that we inserted into the database a few posts ago. The final thing we need to do is to modify our middleware to actually verify that the cookies passed in are legitimate.  First, use npm to install another node module called “async” that allows us to do some synchronous work without too much difficulty.  To do that, let’s create a new top-level directory called “helpers” and create a file called security.js that has these contents:

var async = require('async');
var pg = require('pg');
var connectionString = 
  'tcp://hrtool:password123%25@localhost/hrtool_dev';

exports.checkLogin = function(req, res) {
  async.waterfall([
    function databaseConnect(callback) {
      pg.connect(connectionString, function(err, client) {
        callback(null, client);
      });
    }, 
    function getSessionId(client, callback) {
      client.query("SELECT session_id from users where name=$1",
        [req.cookies.user], function(err, result) {

        callback(err, result);
      });
    },
    function compareSessionId(result, callback) {
      if (result && result.rows && result.rows.length > 0) {
        if (result.rows[0].session_id != req.cookies.session) {
          res.redirect('/login');
        }
      } else {
        res.redirect('/login');
      }
    }
  ], function(err, result) {
    console.log('err = ' + err);
    res.redirect('/login');
  });
};

Now we just need to edit the app.js middleware code we created to call our helper function like this:

var security = require('./helpers/security');

function sessionMiddleware(req, res, next) {
  if (req.url == '/login') {
    next();
  } else {
    if (req.cookies.user == undefined) {
      res.redirect('/login');
    } else if (req.cookies.session == undefined) {
      res.redirect('/login');
    } else {
      security.checkLogin(req, res);
      next();
    }
  }
}
...

At this point, we should be able to re-launch our application from the command-line, delete the cookies we have in the browser and poke around a bit.  Hitting any URL should take us to the /login page.  Entering valid credentials should get us in.  If we delete the cookies and then try to navigate to the / page, then we should end up right back at the /login page.

Posted in Architecture, Security | Tagged , , , | Leave a comment

Next step… designing the login process

In our last post, we created an Express application, a PostgreSQL database and set up a users table to store our user information in a relatively secure way (we used an SHA-1 hash for the password so that it wasn’t stored in plain text).  Now let’s actually set things up so that a user can log into the system and we can validate their identity from that users table.

So what’s our design for this login system?  How do we want to validate the information? How do we set things up so that a user doesn’t have to supply their userid/password for each transaction to the system?  How do we prevent bad guys from slipping in around our login screen and gaining access to pages in our site that should be password protected (something I call “fencing”)?  All good questions that we’ll address one at a time.

  • Validation – There are many approaches we can take on this front, but let’s start simple (we can always beef this up later).  Initially, we will provide a route called /login that has a simple web form on it (retrieved via GET) to collect a userid and password and then does a POST to the same route to validate the information via the form data.  In a production environment, this route should be secured via HTTPS so that the information is encrypted, but for our simple example, let’s stick with HTTP for the time being.
  • Transactions – To support an “authenticated session” model, where the user does not have to supply a userid and password on every transaction, we will use a simple cookie-based session model.  We will have a “user” cookie that stores the email address of our currently logged-in user, and we will also have a “session-id” cookie that stores a UUID that is generated by the server-side upon successful authentication.  On each transaction,we will look up the current session-id of the user, compare it to the one supplied and call them “valid” if they match.  If they don’t (or the cookie information is missing), we will redirect them to the login screen.  Again, in a production system, we would want to use encrypted cookie data, but for now, we will stick with clear text ones to keep things simple.
  • Fencing – To address this, we will leverage a Node.js concept called “middleware”.  We will build a simple piece of middleware that performs an action on every route to check for the existence and validity of the cookies before allowing the route to complete.  If there is a problem, then we redirect to the login screen.

If this makes sense, then we will roll into the actual coding in the next post!

Posted in Architecture, Security | Tagged , , | 1 Comment

Let’s write us some code!

So the first things we need to do is to get a development environment set up.  Since I’m using OSX 10.8 “Mountain Lion”, I found a very nice blog post on how to get node up and running using “homebrew”.  Basically you need to:

Install homebrew:

ruby <(curl -fsSk https://raw.github.com/mxcl/homebrew/go)

Install XCode from the Mac App Store. Once that is done, launch it, go to Preferences the Downloads and install the command line tools.  Next, fix up homebrew using this helpful tip, then install Git:

brew install git

Then install node:

brew install node

Now we need to set up PostgreSQL:

brew install postgresql

Follow the instructions that are printed out on how to set things up after brew finishes up.  That’s it.  Pretty painless.

Now let’s create a working directory for our project and set up the wonderful node-db-migration tool from NearInfinity:

npm install db-migrate -g
npm install express -g
npm install pg -g
express hrtool
cd hrtool

npm install
npm install pg db-migrate

Note the “-g” switch on the npm install lines.  The purpose of this is to install the packages at the global level.  You will need to add in the /usr/local/share/npm/bin directory to your path in your .bash_profile to be sure you have access to the tools.

At this point, we need to create a user and a database.  To do this:

psql -h localhost -d postgres
create role hrtool login password 'password123%';
create database hrtool_dev owner hrtool;
\q

Now that we have a database and a role, let’s set up the configuration file for db-migrate.  Name the file database.json and create it in the root directory of your project.  Add this as the content using your favorite text editor:

{
 "dev": {
 "driver": "pg",
 "user": "hrtool",
 "password": "password123%",
 "host": "localhost",
 "database": "hrtool_dev"
 }
}

Now you need to create a database migration script.  From the root directory of your project:

db-migrate create add-users

This creates a file in my migrations subdirectory that starts with a timestamp and ends with “add-users.js” that we will edit as follows:

var dbm = require('db-migrate');
var type = dbm.dataType;
exports.up = function(db, callback) {
 db.createTable('users', {
 id: { type: 'int', primaryKey: true, autoIncrement: true },
 name: 'string',
 password: 'string',
 updated: 'datetime'
 }, callback);
};
exports.down = function(db, callback) {
 db.dropTable('users', callback);
};

At this point, we can execute our migration and, if all is well, we will discover that we have a new table in the database called “users”:

db-migrate up
psql -h localhost -d hrtool_dev
SELECT column_name FROM information_schema.columns 
WHERE table_name ='users';
\q

You should have seen the columns from your user table.  If that works, you are in good shape at this point.  Now, let’s add an index on the table:

db-migrate create add-users-index

In the file that is created, add the following:

var dbm = require('db-migrate');
var type = dbm.dataType;
exports.up = function(db, callback) {
 db.addIndex('users', 'usersByName', ['name'], callback);
};
exports.down = function(db, callback) {
 db.removeIndex('usersByName', callback);
};

db-migrate up

Finally, let’s add a default user to the system.  We will add a username of ‘admin’ and a password of ‘password123%’.

db-migrate create add-admin-user

var dbm = require('db-migrate');
var type = dbm.dataType;
var crypto = require('crypto');
var shasum = crypto.createHash('sha1');

exports.up = function(db, callback) {
 db.insert('users', ['name', 'password', 'updated'], 
    ['admin', shasum.update('password123%').digest('base64'), 
    '2012-11-01 12:00:00'], callback);
};
exports.down = function(db, callback) {
db.runSql('delete from users where name=?', ['admin'], callback);
};

db-migrate up

This looks like a good stopping point for now.

Posted in Architecture | Tagged , , | 2 Comments

OK… Enough Talk

All right.  I’ve laid out the philosophy for what I intend to build here. I’ve talked about multitenancy, elasticity and statelessness.  So let’s start designing the application that I’ll be building to illustrate this architecture.

The first thing is how we are going to separate the user interface from the business logic.  My strong preference is that the UI be built very simply in HTML5 and use jQuery to talk to a RESTful interface that is exposed by the back-end.  All of the business logic will live behind that API and the only way that work gets done by the UI is through the API.  This is a critical element of the architecture as any enterprise application needs to expose a strong API to not only the customers (for integration purposes) but also to third parties with whom your customers might want to contract, integrate to, etc.

I intend to try and use 100% open source technology to build this application with.  I have  done a startup before using a Microsoft stack and there are many costs that make it challenging to turn the corner to profitability as fast as you might need to in a “shoestring budget” environment.  This will further reduce costs as it will allow me to use lower cost Linux VMs in the EC2 environment versus more expensive closed-source technology.

I will be using PostgreSQL for data storage.  As much as I would like to get into exciting new noSQL database technology, this is the technology that I personally am most comfortable with.  I suppose I could be using mySQL as I actually have more experience with it than I do with PostgreSQL; however, after it became part of Oracle, it seems like the pace of innovation has slowed there.

As this blog is all about building the example application in Node.js, I will be using Node as the technology for my back-end.  This means that, outside of the markup in the HTML5 user-interface and the SQL being executed to persist data, all of the code in this application (be it client or server-side) will be done in Javascript.  Starting to feel like the “wave of the future” folks.

The sample application will be an employee-tracking application similar to an HR Information System (HRIS) that allows employees to log in and update their personal information, managers to transfer employees from department to department, and HR to run a report showing all of this data, rolled up.

In addition to the big decisions, the small ones are summarized below:

  • The application will store state in a set of attribute/value pairs in the database that will be exposed in a global object that we will load on each REST call.
  • API security will be delivered using an API as a Service provider so that we don’t have to build the oAuth2 code on this end.
  • I will be doing all of my development in OSX so your mileage my vary in terms of any configuration issues I speak of in future posts.
  • Production deployment will be done on Ubuntu servers.  I should probably be using CentOS or some other variant but like with the SQL decision, I’m going to stick with what I know.
  • Multitenancy will use the share nothing model where we have a separate database for each customer.  MOTR might have been more exciting to write, but I think this will stretch us more in terms of what it is we are trying to do.

OK.  Next post will start to show code.  Can’t wait!

Posted in Architecture | Tagged , , | Leave a comment

Customization – just another way to say “I’m sorry”

One key differentiator of enterprise software is that you are selling it to large companies. In the time I’ve been doing software and working for software companies, something that I have learned is that the desire for the customer to change their business processes to confirm to your software is inversely proportional to the number of employees that customer has.  In other words, big companies don’t like to change what they do just because they bought your product.

As a result, I have seen various approaches to solving this business problem over the years.  In the 80’s and early 90’s, 4GLs (fourth generation programming  languages) were all the rage. The problem was “solved” but giving the customer access to your application’s source code (typically in a 4GL either custom or “off the shelf”).  They (or your professional services team) could use your product as the base for building what was essentially a custom solution for the end customer.

The pro’s of this approach were that it was the ultimate in flexibility.  If the customer wanted something that your developers and product managers never envisioned, it was just a matter of hiring a programmer, changing the code and away you go.  The con’s were pretty monumental, however.  What happens when you ship v2 of the product and the customer is stuck trying to figure out how to merge their changes and yours and create a whole new custom solution.  Painful…

In the late 90’s and early 2000’s, the move was made to encapsulate customizations in predefined call-outs.  Basically the developers in your product team would put calls at the top and bottom of every key function that the customer or professional services team could use to put their code in to change the behavior of the application.

The upside of this is that the customizations were now cordoned off in their own little world and you could (theoretically) install a new version of your base code without damaging the custom code.  The downside is that if you restructured your code significantly, you would be left with a challenging mess for the customer to clean up.  Sure their customization was still intact, but if it was not being called any more, then they didn’t get what they wanted.

When SaaS applications came onto the scene, things got even more complicated.  Now you are accessing your application through a web browser over the public Internet and you have no access to the production servers.  This means that even if you provided those “hooks” in your back-end code, there was no safe, secure way for the customer to inject their code and get them called.

The solution to this initially was things like workflow technology, custom attributes, etc. Unfortunately this never provided all of the flexibility that you truly need in a large-scale enterprise application.  So how do we solve this thorny problem?

I think the answer today is a combination of many things.  On the data side, extended attributes will get you the storage you need.  Additionally, if you open up a private customer schema in PostgreSQL, you can even have more flexibility without concern that you will collide with your production data model.  For the business logic, this is where Node.js brings a new element to the equation.  It is possible to expose hooks that allow you to let your customers upload Javascript code in those old “user exit” functions that we had in the late 90’s and early 2000’s.

Posted in Architecture | Tagged , , | Leave a comment

Securing your API in the Enterprise

Given the architectural approach we will be taking as we actually build out the sample application of an HTML5 user interface talking via REST to a Node.js back-end using jQuery on the client side, it is imperative that we be certain the API is secure as it will be getting called over the public Internet.  oAuth2 is my current favorite standard to use here; however, even with some of the third party plugins you can get for Node these days, it can be daunting to build this yourself.  Enter vendors like 3Scale and Mashery.

API Provider as a Service (I’m sure there is some XaaS acronym for this that I just don’t know) is a fairly new concept in enterprise, and even consumer software.  Basically the idea is that you can outsource much of your API infrastructure to a third party who will front-end your API for you. While that sounds a bit odd at first, there are some real advantages here.

  • Key Management – These services provide a web user interface for developers to sign up, be issued keys, manage the keys (i.e. revoke them if necessary), etc.  If you don’t use a service like this, keep in mind you will either have to manually manage this, or build the tool yourself as part of your application infrastructure.
  • API Documentation – These services also allow you to easily create documentation for 3rd party developers who use your API.  In the Mashery case, there are even interactive tools on their developer portal that allow the user to create calls and execute them so that they can see the result set.
  • Rate Limiting – Building this capability into your architecture can be very challenging. These services do this for a living and make it very easy for you to specify which class of service a particular developer qualifies for and can rate limit, data limit, call limit, etc. for you without you having to write this code.
  • Security – Writing oAuth2 server code can be challenging even with off the shelf plugins and libraries.  These services allow to blanket ignore API calls from everyone except their known IP addresses (white-listing) and then let them manage all of that security for you.  In addition they can support multiple “auth” methods without you having to write that code.
  • Protocol Transformation – If you are building something completely new, then this is not an issue for you.  However, if you have an existing SOAP API that you expose to customers, these services can allow you to expose a REST version of it that proxies the calls to SOAP behind the scene.  This can be a real time saver in terms of rolling out new technology to your 3rd party developers without having to invest in the R&D costs of spinning up an entirely new API technology on your side.

All in all there are many advantages to using a service like this.  I would strongly encourage everyone to look into them as opposed to continuing to roll your own.

Posted in Security | Tagged , , | Leave a comment

Run and maintain

An often overlooked aspect of multitenant SaaS enterprise software development (at least by startups trying to create it), is that there is so much more to the product than just building it.  Specifically, how do you deploy and maintain the product in the production environment once you have released it.  We have talked so far about elasticity, which handles the creation of additional compute capacity on demand, but there is another element of the equation that is just as challenging – maintaining the production datamodel over time.

In all of the enterprise  software companies I have been associated with over the years, this is a problem that is solved in much the same way, with varying degrees of polish.  The problem is this – how do you apply changes to the datamodel over time, keep track of what you have applied and what you haven’t, and then put those changes into the production environment across possibly hundreds of customer databases (if you use the “share nothing” approach to multitenancy).

Ruby on Rails has a great solution to this with the “rake db:migrate” command and its friends.  Basically the idea is that you create individual datamodel migrations that can be played much like a cassette tape – serially applying the changes to a database.  The really nice thing about these tools is that you can point them at a database that is, perhaps, halfway through the migration process and it can figure out which steps have been applied and which haven’t yet.

In other places I have worked, we have built similar tools from scratch.  Essentially they all have the same characteristics:

  • Versioning – Assigning a unique identifier to each change that is to be made to the datamodel so that you can speak of change ID “X” and know which database code to execute to manage the migration.
  • Tracking – Keeping track of which changes (by change ID) have been applied to the datamodel so that you know which ones still have to be executed to bring the datamodel up to date.
  • Execution – Looking at the list of changes that need to be applied, seeing which ones already have been applied and then executing each of the unapplied changes to bring the datamodel up to date.

Earlier in this post, I mentioned that I have seen these techniques applied with varying degrees of polish.  The things that truly differentiate this include:

  • Sequencing – Knowing that some changes are dependent upon other changes so that they can be executed in the right order to produce the right outcome.  For example, if one change creates a column and another indexes that column, then they need to be ran in the right order to avoid trying to index a column that doesn’t exist.
  • Error Handling – Inevitably the production environment will raise challenges that the developers of the various migration scripts did not anticipate.  How errors are handled in these cases is critical as you don’t want to have a migration step half applied then try to re-apply it when the script is corrected.  In simple cases, just wrapping a transaction around the migration step might suffice; however, in high transaction environments, this can become problematic with locking concerns in a production database.
  • Developer tools – Simple things like assigning a change ID to a developer to developer their script can be challenging.  Many places I have worked just used a sequential number and counted on the developer to make sure they grab the next one in a sequence.  For small teams, this could possibly work.  For large teams, using UUIDs or other techniques (Rails uses timestamps combined with human-readable names) is the right solution.
  • Batching – For production databases under profound pressure, some migration steps can take far too long and start causing problems with the production environment.  In those cases, it is best to split the work into small batches that can be committed and tracked.
Posted in Uncategorized | Tagged , , , | Leave a comment

Enterprise Software – A definintion

So at various points in my posts on this blog, I have referred to building multitenant enterprise SaaS software.  I think we have a good working definition of multitenant and SaaS is pretty clear.  However, I think the term “enterprise software” gets a bit more murky.  What are the unique characteristics of enterprise software in a SaaS environment and how do we need to construct an architecture that makes a product successful?

Enterprise vs. Consumer

  • Users – In a typical multitenant consumer application, each user’s data is partitioned separately from every other user.  However, in an enterprise software product, the users need to have visibility to the work that other users do within their company  and yet still be partitioned on the company level.
  • Security – In a typical enterprise software product, security is managed by the customer, not by the application’s author.  This means that technologies like SSO (single sign-on) become very important.  Oddly though, the quality of the software and its architecture become very important from a security perspective as the author’s company will be often put through security audits, penetration tests, etc.  However, the direct management of the security of the application itself will be in the hands of the customer.
  • Provisioning – In consumer software, it is very common to see a “click here to sign up” link on the login screen for the product.  For enterprise software, the provisioning of new users is typically managed by the customer’s administrators and is completely out of the hands of the company that builds the software.
  • Rights & Roles – Enterprise software requires that users be able to collaborate in the movement of work through the system.  To do this, however, requires that a user only be exposed to the functionality and data that are necessary for their part of the collaboration – and no more (similar to the principle of “least access” in security circles).  As a result, it is often important for the product to support special security rights that enable / disable access to key pieces of data.  Also a role-based user interface becomes very important to avoid the dread trap of “customization”.
  • Customization – Typically enterprise software is software that is sold to very large companies.  A natural component of the sales cycle is what I like to call the “but this is how WE do it” element.  Large companies would much rather bend the software to their processes rather than change their processes to adhere to the intended design and behavior of the software.  Even when it can be “proven” that the product’s natural state is considered an industry best practice, there needs to be an ability to change that behavior when it becomes inconvenient to closing the sales based on how the customer wants to operate.

So, in conclusion, enterprise software is software that allows users to be grouped and managed, with a role-based interface that is flexible and allows itself to be adapted around the processes of the customer.  Sound easy enough?

Now that we have all of the definition out of the way, the next step in our journey will be to define the baseline architectural requirements of a true multitenant enterprise SaaS application, leveraging the goodness that is present in the Node.js framework.

Posted in Architecture | Tagged , , | Leave a comment

Elasticity – What is it?

In my last post, I mentioned a term called “elasticity” as something all enterprise applications should strive to achieve.  Essentially what it is, is the ability for a running multitenant, enterprise SaaS system to monitor itself, and add or remove computing resources as is necessary to  deliver appropriate levels of performance to its end users.

To achieve elasticity, I would contend that you must be running on a third party hosted service such as Amazon EC-2 and have each physical tier of your application available to the master controller in a set of “dehydrated” virtual machines.  In other words, if you have API servers, you need to have a version of an API server saved off and capable of being launched in an on demand fashion so that it can be added to the pool of API servers.

Accomplishing this feat in your application is challenging.  There are several “gotchas” to consider in terms of your design.  Specifically:

  • Make sure your application is stateless.  If not, then adding additional servers will accomplish nothing in terms of providing additional headroom for your already logged-in users.
  • Instrument, instrument, instrument.  Make sure that each of your servers has appropriate instrumentation hooks for a technology like Nagios that will allow critical performance elements such as CPU utilization, free memory, I/O performance, etc. to be monitored.  Without this raw data, your supervisor program will not know when a given tier of the application is in trouble and needing additional resources.
  • Build a fault-tolerant supervisor process that can monitor the output of your instrumentation.  If this supervisor process crashes and is not successfully restarted, your application has just lost its elasticity.
  • What goes up should be able to come down. If you don’t build in rules to your supervisor program that allow it to decommission virtual machines when things settle down in a given tier of your application, you only have unidirectional elasticity and that means you will be paying for servers that are doing little or no work in your off peak hours.
  • Put in boundaries.  If you simply say, keep adding servers at the API tier when CPU utilization goes over 90%, you could see yourself paying a huge bill at Amazon if you write an infinite loop into your code, get DDOS’ed from a bad guy, etc.

All in all, elasticity is a beautiful concept for a multitenant enterprise SaaS application’s architecture.  If considered early and built in from day one, it will dramatically reduce your application’s run and maintain costs and will allow you to deliver higher service levels and more consistent performance to your customers.

Posted in Architecture | Tagged , , | 1 Comment

Application State – We all want to be Stateless

In one of my earlier posts, I mentioned that in a share nothing data partitioning model, you have the cost of standing up your database connection to your customer-specific database adding significantly to the latency of your application.  In the post, I mentioned this was because you designed your application to be stateless, not stateful.  As I was writing this, I realized that the topic of state is one that is not to be underestimated in terms of its impact on the ultimate scalability of your multitenant SaaS application.

Essentially, an application can be architected in such a way that it preserves no user state (field values, connections, etc.) from one transaction to the next.  By doing this, you are allowing your application to ultimately be more scalable because you can service those transactions from a pool of web servers.  In other words, when the transaction comes in from a user clicking something on your web page, it doesn’t care which server services the request because any of them can do it.

Unfortunately, in a lot of legacy applications, you find stateful behaviors.  A great example of this is data that is preserved in memory as a user takes a multi-step process through to its conclusion.  Since this data lives in RAM as opposed to your application’s database, the server whose RAM the information is stored in is required to service the individual customer’s transactions until the data is saved to the database persistently.

A better model would be to store each transaction’s information in the database in a “draft” or “in progress” state so that nothing would tie a transaction to a specific user.  This allows the application to have an arbitrary number of servers added to the pool to support the load being placed on those servers by the then-current transactional volume. If you do this in an automated fashion, you gain something that is known as “elasticity”, but that’s a topic for a later post.

Building a stateless application is sometimes a real challenge, especially if you have a high degree of interactivity on your page with multiple AJAX callbacks, etc.  However, making the effort to invest in this capability will pay off if you ever expect your application to scale to enterprise software levels.

As a general pattern, the approach that I have seen work the best over the years is to maintain a table in your application’s database with attribute / value pairs in which you persist the necessary state information that needs to exist beyond the scope of the current user’s transaction, keyed by a session ID.  You can add code as part of your initialization process on the server side to load the data into RAM and then access it as needed during your transaction.

It is important to use a globally unique session ID (a GUID or UUID depending on your school of thought) versus just tying the state data to a user ID.  By taking this approach, you allow your user to potentially be logged into multiple instances of your application at the same time and each session will be logically isolated from the other.  If this isn’t a use case you ever intend on supporting (now or in the future) for your application, then you can probably get away with tying it to the user ID.

One other thing you should do to support this pattern is maintain an active session table in your database as well.  By keeping a timestamp on the last time the session was active, you can either have a batch process that kills sessions after X minutes of inactivity, or can have the login process for a new users do that clean up on your behalf.  If you take the latter approach (I tend to abhor batch processing in my applications as it adds unnecessary complexity), just be aware that you probably should do this ahead of any authentication code you have to prevent a user from skating past your session timeout limits if they happen to be the first person to log in after their session has expired.

In conclusion, stateless web application are far more flexible and scalable than their stateful counterparts.  If possibly, you should always strive to create an architecture that incorporates this.

Posted in Architecture | Tagged , , , | 1 Comment