We recently had some memory issues we were investigating that were only happening on our
local servers. It led to a few interesting discoveries that I thought I would highlight here.
There are many “development only” settings in the
config/ColdBox.cfc configuration file. In our naïvety, we turned them all on for our
dev environments. We were trying to avoid having to remember to
fwreinit our application as that was something we didn’t deal with in our homegrown system.
Well, even with turning on all those settings, I think we still basically reinited our application the same amount, not sure if we had missed a “development only” setting. So, it didn’t save us any time. It actually cost us more time and, as I will show, introduced a situation where our memory usage got quickly out of hand.
Let’s go over two settings that I think are a bit of anti-patterns (and the docs agree with me, though I ignored that when I started 😉):
We’ll start with the more innocuous one. This setting promises to reload all singletons on every request. At first glance, this sounds great. No more remembering to reinit your application when you change a singleton. It also, however, introduces a few drawbacks.
First, it can be a lot of overhead. Singletons are a great pattern because they don’t need to be recreated over and over again. This setting throws all those savings away and the overhead added to recreate each one can be quite substantial, even up to a few seconds per request.
Second, it’s not thread safe. Every request, including ajax requests, will recreate all singletons. If a subsequent request tearsdown and rebuilds all singletons while the first one is in process, the first one could have some funky errors. I say could because it is a classic race condition, the worst things to debug. You might have run in to this yourself and never known why the error only sometimes happened. Here’s a likely candidate.
So what’s the solution?
fwreinit when you need to reload a singleton. Yes, when you are working on a singleton exclusively, it will be reloading every request, but when you are not you are gaining a nice performance boost and avoiding some nasty race conditions.
On the surface, this setting looks like it has all the same benefits and drawbacks as
wirebox.singletonReload = true. It can add a lot of overhead and is not thread safe. The major issues come from some interactions with common modules.
The module that caused us a bunch of issues was
cbjavaloader. This is not due to any fault of
cbjavaloader, but rather our understanding of it (or lack of, in this case). Every time a module that used
cbjavaloader was reloaded, all the jars would be loaded in to memory. Combine that with reload every module on every request and you can see how memory usage could explode!
(On a side note: I think there’s a bug with
cbjavaloader not remembering previously loaded urls. I’ve filed a bug.)
Now, to Ortus’s defense, they have discalimers on both of those settings about how it could make your application unstable. But I want to circle back to what I said at the beginning about how our team still always includes
fwreinit when we are developing because we have no idea if we got all the settings. In our case (and I would venture to guess many others) we not only are not getting any benefit from these settings, but they are actively causing us more issues.
To that end, I’ve filed a request to remove
modules.autoReload from the next major version of ColdBox, ColdBox 5. If you agree or disagree, come add your voice to the ticket.
Oh, and probably go turn those settings off in your own app.