In order to manage the database context at the bottom of the stack I'm having to create a small framework that does stuff as the code enters the managed context and leaves. So the easiest way to use the framework is if you have

new Runnable() {
        public void run() {....}
}

in your code somewhere you just instead just do

new ManagedContextRunnable() {
        public void doRun {...}
}

Additionally for places where there is no runnable at the bottom of the stack (like ApiServer), there is a simple API as below.

public interface ManagedContext {
    public void runWithContext(Runnable run);

public <T> T callWithContext(Callable<T> callable) throws Exception;

    public void registerListener(ManagedContextListener<?> listener);

    public void unregisterListener(ManagedContextListener<?> listener);
}

The (un)register methods are for registering listeners to do stuff as things enter/leave the context (like setup the transaction, etc).

Now this gets to my question. So this is yet another context thread local thing that needs to be setup. So I'm somewhat trying to tie the CallContext, ServerContext, AsyncJobExecutionContext, and this together. So the "managed context" framework is the central place to wire this all up. Here's what I'm doing, tell me if its terribly bad.

CallContext: One thing I see with the CallContext is that its really easy to register twice and then leak the NDC stack. What I propose is that on entering the ManagedContext I will setup the CallContext with a context that has the user as system and the context id as random. As people call register/unregister it will push/pop a CallContext on some stack and additionally push/pop the NDC. When leaving the ManagedContext I will ensure that all CallContexts are pop'd off the stack, thus clearing the NDC. This approach has the added benefit that by default the context will be setup as system and then all background tasks don't explicitly have to call register(...)

ServerContexts: Just delete it? Basically it seems to just open/close transaction and I'll be doing that anyhow. It doesn't seem to really be used yet. Maybe my "Manage Context" framework essentially is in the spirit of what that was going to be?

AsyncJobExecutionContext: Not too much, I can just ensure that the AsyncJobExecutionContext is cleared on exit.


On last thought (sorry this is long). I also created the concept of a ManagedThreadLocal. Its like one thread local to rule them all. Thread locals are fine, but people forget to clear them. So what you do is have a "managed thread local" that looks and acts just like a TL but is really tied to a master TL. When the main context of the thread clears, the master TL is cleared and all associated managed TLs will be cleared too. Then you don't ever leak TLs.

Darren

Reply via email to