diff --git a/GrailsflowGrailsPlugin.groovy b/GrailsflowGrailsPlugin.groovy index df3560d..21f97e1 100644 --- a/GrailsflowGrailsPlugin.groovy +++ b/GrailsflowGrailsPlugin.groovy @@ -11,7 +11,7 @@ import com.jcatalog.grailsflow.status.ProcessStatusEnum import com.jcatalog.grailsflow.scheduling.triggers.ConfigurableSimpleTrigger class GrailsflowGrailsPlugin { - def version = "1.9.3-SNAPSHOT" + def version = "1.9.3-issue-49-SNAPSHOT" // the version or versions of Grails the plugin is designed for def grailsVersion = "2.3 > *" def dependsOn = [quartz: "1.0.1 > *"] diff --git a/grails-app/services/com/jcatalog/grailsflow/ProcessManagerService.groovy b/grails-app/services/com/jcatalog/grailsflow/ProcessManagerService.groovy index e67ebe7..9f0401e 100644 --- a/grails-app/services/com/jcatalog/grailsflow/ProcessManagerService.groovy +++ b/grails-app/services/com/jcatalog/grailsflow/ProcessManagerService.groovy @@ -42,6 +42,8 @@ import com.jcatalog.grailsflow.extension.SendEventParameters import com.jcatalog.grailsflow.engine.concurrent.ProcessLock import grails.util.Environment + +import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.concurrent.Callable import org.springframework.transaction.support.TransactionSynchronizationManager @@ -57,6 +59,9 @@ import com.jcatalog.grailsflow.process.PostKillProcessHandler import org.springframework.transaction.TransactionStatus import org.quartz.ObjectAlreadyExistsException import org.quartz.SimpleTrigger + +import java.util.concurrent.Future + import static org.quartz.TriggerKey.*; import java.util.concurrent.ThreadFactory import com.jcatalog.grailsflow.status.ProcessStatusEnum @@ -1295,11 +1300,14 @@ class ProcessManagerService implements InitializingBean { log.debug("Executing node '${node.nodeID}' of process #${node.process?.id}(${node.process?.type})") Closure actionsCode = processClass.nodeActions[node.nodeID] // execute actions in separate session (creation a separate thread) - return Executors.newSingleThreadExecutor( new ThreadFactory() { + // This is important to put new instance to the separate variable to resolve the existed JDK issue + // https://bugs.openjdk.java.net/browse/JDK-8145304 + + ThreadFactory threadFactory = new ThreadFactory() { public Thread newThread(Runnable r) { SecurityManager s = System.getSecurityManager(); def group = (s != null)? s.getThreadGroup() : - Thread.currentThread().getThreadGroup(); + Thread.currentThread().getThreadGroup(); def namePrefix = "#${node.process?.id}(${node.process?.type})-${node.nodeID}" Thread t = new Thread(group, r, namePrefix, 0); if (t.isDaemon()) @@ -1313,7 +1321,12 @@ class ProcessManagerService implements InitializingBean { notifier.invocationThreadLock.writeLock().unlock() return t; } - }).submit( { + } + + final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1, threadFactory ) + final ExecutorService threadExecutor = Executors.unconfigurableExecutorService(fixedThreadPool) + + final Future futureTask = threadExecutor.submit( { def result try { Session session = SessionFactoryUtils.getNewSession(sessionFactory) @@ -1381,7 +1394,12 @@ class ProcessManagerService implements InitializingBean { } } return result - } as Callable ).get() + } as Callable ) + + def threadExecutionResult = futureTask.get() + threadExecutor.shutdown() + + return threadExecutionResult }