[CommandBox 3.8.0] Differences between CommandBox embedded server and standalone Lucee

I’m seeing some differences in the behavior of the CommandBox embedded server and a standalone Lucee install. Both are tough to communicate meaningfully here, so I’m just going to sketch briefly.

I’m looking for reasons why the exact same Lucee version would behave differently in those two environments. I’m semi-accidentally being the canary in the coal mine, trying to see if it makes sense for developers here to use CommandBox/CFConfig to manage their dev environments. The logistics are great – instantly run the same code, dbs, mappings, settings, etc, against different CFML engines, perfect – but if doesn’t act like a “real” engine install, we’d spend time chasing bugs that only exist under CB, or missing ones that don’t happen there but do standalone.

First difference is a ‘java.util.ConcurrentModificationException’ crash in the real app I’m working on (big and complex), when it does structClear(Request). (It does that to work around a Lucee bug where structs are duplicated when they’re passed into Java objects; we’ve reported it.) The crash only happens under CommandBox, not standalone Lucee. I can’t reproduce the ConcurrentModificationException in standalone code outside the app, and I can modify the app slightly to avoid it, but that’s not the point.

Does anyone have any idea why the exact same Lucee version acts differently in that respect under CommandBox than standalone?

Second thing is that some of the java args we have as part of our standard Lucee config prevent the embedded server from starting. I haven’t had a chance to work out exactly which ones, and I’ve been able to get going with a limited set of them, so I’m not dead in the water. It’s also possible I don’t have the right args between ACF and Lucee, will investigate.

But again the point is, should there be any differences on that level between standalone Lucee or ACF and the same engine version running under CommandBox?

Thanks in advance for any thoughts.

Dave,

I’m not sure why the structClear behavior is different between the two. structClear should never really be used on the request scope ( or any implicit scopes which contain complex objects ) because of this very reason.

If a complex object is being stored in the request scope, then using structClear is “iffy” because the variables scope of that object also is a part of the scope being cleared – hence concurrent modification exception when attempting a non-iterative clearing of the struct/map. Same thing with keys within the request which are referenced within the other complex objects of the scope or are being run within a closure that references an item in the scope being cleared. I’ve seen this same error when code uses structClear on the session scope, as well.

If you dump the metadata of the request scope, you’ll see that it’s not a simple Java “Map” class or a Lucee implicit struct, but it’s actually a custom Java object: lucee.runtime.type.scope.RequestImpl. Which version of Lucee is your previous installation running on ( major.minor.patch )? There may be a difference in the implementation of that class between the previous installation and your current one.

As far as your java arguments are concerned, there are a few things which may be causing the different behavior ( e.g. – the errors ):

  • The servlet container – the standalone Lucee install uses Tomcat as its servlet container. Commandbox uses Runwar/Undertow. As such, there may be differences in how the servlet container is handling those java arguments. You may want to start your server with the --debug flag to see where the error is occurring.
  • Your Java version. There are big differences, especially with regard to memory space usage between Java 7 and Java 8. Unless you tell it otherwise, your CommandBox install is going to use the default JAVA_HOME. The Lucee installation you are working with may be using a different Java version and some of the java args may need to be tweaked for the different Java version. Since CommandBox can run on either 7 or 8, you can always change that if you need to.

Jon

Thanks for jumping in Jon, as always :slight_smile:

Are you saying that structClear() also clears any child structs it contains? I didn’t think that was true, and just verified that it’s not, at least on Lucee 5.2.2.71. As I said, structClear(Request) is a workaround for the fact that Lucee apparently does a deep copy of any complex objects it passes into a java method. I wasn’t the person here who dug into that, but my understanding is that it does happen, and in our case it causes prohibitive performance problems. We’ve reported it I think.

Thanks for the debugging ideas on the java args. Java versions are the same.

I’m aware that the underlying servlet containers are different, but it actually matters a lot to me to what extent they behave differently. They’re similar enough that in my very limited testing I’ve only hit these few differences. I’d hate to abandon CommandBox as a dev environment just because I’m scared there may be problems I haven’t seen.

Dave

Jon wasn’t saying that the struct clear would affect complex objects, I think he was just saying that your code was not a good idea :slight_smile:

I’m not aware of any reason at all why that would behave differently though, and I’ve never seen that myself. Are you on the exact same version of Lucee? If you can come up with a repro case, I would enter in a ticket. Since that error is some sort of race condition with two threads trying to operate on the same struct, it’s likely there’s several obscure possibilities why one server might be hitting the code at a slightly different time.

Regarding the JVM args, you need to tell us what your args are. There’s like 27 billion different JVM args out there, many of which only apply to specific combinations of servers. Just saying that you’ve found a couple that are giving you issues doesn’t help. The short answer is, no there’s no obvious reason why a given jvm arg wouldn’t work on CommandBox-- it’s just a java process like any other server. The slightly longer answer is, yeah there’s a lot of reasons a specific arg might not work on a given setup. The first possibility is that you didn’t escape it correctly in your JSON. Start by running a --debug --console start and verifying that the JVM args in the debug output look correct.

Thanks!

~Brad

ColdBox/CommandBox Developer Advocate
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

> “Are you saying that structClear() also clears any child structs it contains?”

No, just that, if a component exists in the request scope and it contains additional objects in its variables scope, the attempt to wipe the object clear is going have to deal with multiple references nested within the scope – which facilitates the concurrent modification exception. It doesn’t clear the references within the object, unless those references are not used anywhere else – in which case they are garbage collected.

structClear clears everything in the struct, non-iteratively, which is why you get the concurrent modification exceptions. If you Google this java error, you’ll see basically the same answer over and over again: Clear iteratively because clear() ( the native member function – which works like structClear() ) invites this exception. To clear it iternatively is fairly straightforward : for( var key in request ) structDelete( request, key );

All that said, that doesn’t mean it wouldn’t be a good idea for Lucee to handle that more gracefully. Adding a bug report for the error wouldn’t be a bad idea: https://luceeserver.atlassian.net

> “Lucee apparently does a deep copy of any complex objects it passes into a java method”

What kind of Java methods are we talking about? I’m not seeing that behavior, at all and most of the modules I develop for Ortus use Java methods heavily.

@Brad, this can be duplicated on a Coldbox app by attempting to run structClear on the REQUEST inside of the bootstrap request. The cbox_requestcontext is one example of an object that will throw this error.

Jon