I should mention that the work-around shown above should NOT be placed in all of your project library scripts. It solves the multiple execution problem but at the risk of AB-BA deadlock across interdependent scripts. Some thoughts:
-
Definitions of simple functions and simple assignments to top-level constants do not need this fix. While multiple executions will repeatedly replace top level objects, the replacements are identical to the first pass--no harm, no foul.
-
Definitions of top-level objects to be used as deletable/clearable caches are also effectively unharmed by multiple initialization, though some cache entries established early (while racing) might be blown away.
-
Definitions of utility classes that have short lifetimes are similarly unaffected. That early instances might not have the same type as later instances (because the class was redefined multiple times) is meaningless for such cases--the instances don't live long enough for that to matter, and the implementations are identical.
-
Establishing top-level dictionaries with my
system.util.globalVarMap()
or the nativesystem.util.getGlobals()
to obtain JVM-lifetime persistent storage is safe. Values placed in such dictionaries with.setdefault()
are also unaffected by repeat initialization.
Scenarios that DO need this fix:
-
Jython classes that establish singleton instances during initialization. Multiple singletons will be created, and those grabbed early will not have the same state as the last one.
-
Top level constants that are assembled in multiple steps, using
+=
orlist.append()
operations, will be corrupted in odd ways by the parallel execution. (Encountered this a lot some years ago--I had to stop doing that.) -
Top level objects that form the root of linked object relationships are vulnerable. Early linkages may be chopped off by the repeat initialization and those linked objects' memory leaked.
-
Scripts that launch asynchronous threads during initialization will launch multiples, with potentially long-lived clashing behavior.
-
Top level constants initialized from database queries, web API requests, or other time-consuming operations (particularly when calling a function just defined locally) will race and race and race the whole time the first execution runs, and the last execution may leave the constant with errors if any resource has rate limits.
The fix I recommended to IA in my bug report does not have the AB-BA deadlock risk, so hopefully this all becomes moot.