We have an app that runs on Payara and has a bunch of scheduled quartz jobs running. After 25 days of continous running we’ve noticed that the app consumes 95% of heap so we took a heap dump and after analyzing it it shows that its queue in SheduledThreadPoolExecutor that is retaining bilions (116 bilions in our case) RunnabeScheduledFutures.
After further search we’ve discovered that said executor is scheduledTransactionManagerExecutor from JavaEETransactionManagerSimplified.
Executor does not have the property to remove on cancel set, instead there is a code in the constructor to set future to remove canceled tasks after certain ammount of cancelation:
public JavaEETransactionManagerSimplified() {
transactions = new ThreadLocal<>();
localCallCounter = new ThreadLocal<>();
delegates = new ThreadLocal<>();
scheduledTransactionManagerExecutor = new ScheduledThreadPoolExecutor(
Math.min(Runtime.getRuntime().availableProcessors(), 3)
);
if (getPurgeCancelledTtransactionsAfter() > 0) {
purgeScheduledTransactionsFuture = scheduledTransactionManagerExecutor.scheduleAtFixedRate(
this::purgeCancelledTransactionTimeouts, 5, 5, TimeUnit.SECONDS
);
}
}
We have this property set in our domain.xml like so
<transaction-service automatic-recovery="true" tx-log-dir="${com.sun.aas.instanceRoot}/logs" timeout-in-seconds="300">
<property name="xaresource-txn-timeout" value="300"></property>
<property name="purge-cancelled-transactions-after" value="500"></property>
</transaction-service>
hovewer when the constructor is called this property is equal to 0, which makes sense for it is not set anywhere before, so the future is not created. The property is read properly with our value 500 in initProperties() method with
String v = txnService.getPropertyValue("purge-cancelled-transactions-after");
if (v != null && v.length() > 0) {
purgeCancelledTtransactions = Integer.parseInt(v);
}
however the future is not created there after reading that, so the cleanup is non existant. Cancelled task pille up over time.
I’m not sure if it is something on our end with our config, however looking at the class i dont see how it is ever supposed to work. The property read in constructor is not set before and only chance for it to work is with a custom manager that overrides it.
Should we do that and write our own manager or is there something we should configure in domain.xml to use different manager?