Multitenancy in Google App Engine: Scope of NamespaceManager

Posted on Thursday, September 16, 2010

2


As you would have read in our previous post, we used the Namespace API to make the SaaS application that we were working on multi-tenant in a matter of four hours.

You would have noticed that we set the tenant name in the NamespaceManager

NamespaceManager.set(request.getServerName());

Our initial assumption was that the NamespaceManager would continue to exist for the lifetime of the session since we would have one tenant logging in and would remain the same till he logs out. Supposedly, this is not the case. NamespaceManager is scoped to a single request and is stored in a thread-local.

The advantage of thread-local being that a variable being stored as thread-local is associated with that particular thread and is not shared. All the threads in the same process might share the static variables as they reside in the same memory space but the thread-local variables reside on the stack and every thread has its own stack.

What is the advantage of doing it this way?

Well the first advantage is that since it is coming with each request, I could potentially change the Namespace temporarily for an operation and set it back to the original namespace. I am not bound by the fact that it would have to remain the same for the session/ application scope. So I could do something like this,

String oldNamespace = NamespaceManager.get();
NamespaceManager.set("abc");
try {
 ... perform operation using current namespace ...
} finally {
 NamespaceManager.set(oldNamespace);
}

Also, since it is not stored in any static variable, I am assured that there would be no data leakage with one tenant accessing the namespace of another.

Now, what is the pitfall of doing it this way?

For an application like ours where tenants are identified by subdomains, for example abc.bookmyhours.com and xyz.bookmyhours.com, each tenant enters the application with their own subdomain. Now, for the remainder of the session, they continue to be in the same namespace.

Irrespective of this, since we use a filter for namespace filtering, we would parse each request to get the servername and set the NamespaceManager. This might not sound very heavy and still might be acceptable to do with each request. What made it worse in our case was that whenever a new namespace tenant comes for the first time, we set up seed data for that namespace. Then for subsequent calls we see that the data exists and hence we should not set up the seed data. Nevertheless, there is always a call made to the database to check if the data exists with each request.

Not a good design at all and may be we would have to explore that we need to set up seed data somewhere else, but for some applications this may be a requirement and that is where the proposed solution would come in handy.

For now, we set the namespace variable in the user session. So the code looks like

String sessionNameSpace = httpSession.getAttribute("nameSpace");
if (sessionNameSpace == null) {
      seedDataSetup.setSeedData();
      httpSession.setAttribute("nameSpace", request.getServerName());
}
NamespaceManager.set(httpSession.getAttribute("nameSpace"));

The NamespaceManager.set() has to be done with each request since it is thread-local, however you can do away with parsing the request and/or any other complex logic that you have in the filter by using the session.

About these ads
Posted in: Architecture, Cloud, Java