Search in sources :

Example 1 with Execution

use of com.disney.groovity.stats.GroovityStatistics.Execution in project groovity by disney.

the class Async method tag.

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object tag(Map attributes, final Closure body) throws Exception {
    final Integer timeoutSeconds = resolve(attributes, TIMEOUT, Integer.class);
    final ScriptHelper scriptHelper = getScriptHelper(body);
    final Binding binding = scriptHelper.getBinding();
    final Map variables = binding.getVariables();
    final AwaitContext asyncContext = AwaitContext.get(variables);
    DeadlockFreeExecutor createdThreadPool = null;
    // make a copy of current binding for async
    final Map asyncVariables = asyncCopy(variables);
    if (asyncContext == null || !asyncVariables.containsKey(Async.EXECUTOR_BINDING)) {
        Integer numThreads = resolve(attributes, POOL, Integer.class);
        if (numThreads != null) {
            createdThreadPool = new DeadlockFreeExecutor(interruptFactory, numThreads);
            asyncVariables.put(EXECUTOR_BINDING, createdThreadPool);
        }
    }
    final DeadlockFreeExecutor asyncPool = createdThreadPool != null ? createdThreadPool : ((asyncContext != null) ? getExecutor(asyncVariables) : sharedThreadPool);
    final boolean shutdownPool = createdThreadPool != null;
    final CharArrayWriter out = new CharArrayWriter();
    asyncVariables.put(OUT, out);
    if (asyncContext != null) {
        // signal a boundary for sequencing async output
        asyncContext.signalAsync(variables, out);
    }
    final Execution parentStack = asyncContext != null ? asyncContext.getWaitingExecution() : null;
    String scriptPath = scriptHelper.getClassLoader().getScriptName();
    final long timeoutTime = timeoutSeconds == null ? -1 : System.currentTimeMillis() + (timeoutSeconds * 1000);
    final Callable<Object> bodyRunner = new Callable<Object>() {

        @Override
        public Object call() throws Exception {
            Binding asyncBinding = new Binding(asyncVariables);
            Binding oldThreadBinding = ScriptHelper.THREAD_BINDING.get();
            ScriptHelper.THREAD_BINDING.set(asyncBinding);
            final Execution restoreStack = parentStack != null ? GroovityStatistics.registerStack(parentStack) : null;
            try {
                Closure asyncBody;
                if (body.getThisObject() instanceof Class) {
                    // if the parent script is not available it is a special case (static) and we may share the context
                    asyncBody = body;
                    asyncBody.setDelegate(asyncBinding);
                    asyncBody.setResolveStrategy(Closure.DELEGATE_FIRST);
                } else {
                    Script asyncInstance = scriptHelper.load(scriptPath);
                    asyncBody = body.rehydrate(asyncInstance, asyncInstance, asyncInstance);
                }
                if (timeoutTime > 0) {
                    // use an interrupt to enforce the timeout
                    long startTime = System.currentTimeMillis();
                    if (startTime > timeoutTime) {
                        throw new InterruptedException();
                    }
                    final ScheduledFuture<?> interrupt = interruptFactory.scheduleInterrupt(timeoutTime - startTime);
                    try {
                        return asyncBody.call();
                    } finally {
                        interrupt.cancel(true);
                    }
                }
                return asyncBody.call();
            } catch (Throwable e) {
                if (asyncContext == null) {
                    // with no known waiters this exception could get lost, let's log it
                    log.log(Level.SEVERE, "Error in async", e);
                }
                throw e;
            } finally {
                if (oldThreadBinding == null) {
                    ScriptHelper.THREAD_BINDING.remove();
                } else {
                    ScriptHelper.THREAD_BINDING.set(oldThreadBinding);
                }
                if (parentStack != null) {
                    GroovityStatistics.registerStack(restoreStack);
                }
                if (shutdownPool) {
                    sharedThreadPool.submit(new Runnable() {

                        @Override
                        public void run() {
                            asyncPool.shutdown();
                            try {
                                if (!asyncPool.awaitTermination(60, TimeUnit.SECONDS)) {
                                    asyncPool.shutdownNow();
                                    asyncPool.awaitTermination(60, TimeUnit.SECONDS);
                                }
                            } catch (InterruptedException e) {
                                asyncPool.shutdownNow();
                            }
                        }
                    });
                }
            }
        }
    };
    Future<Object> future = asyncPool.submit(bodyRunner);
    if (asyncContext != null) {
        asyncContext.add(future);
    }
    String var = resolve(attributes, VAR, String.class);
    if (var != null && var.length() > 0) {
        variables.put(var, future);
    }
    return future;
}
Also used : Binding(groovy.lang.Binding) Script(groovy.lang.Script) Closure(groovy.lang.Closure) CharArrayWriter(java.io.CharArrayWriter) Callable(java.util.concurrent.Callable) Execution(com.disney.groovity.stats.GroovityStatistics.Execution) ScriptHelper(com.disney.groovity.util.ScriptHelper) HashMap(java.util.HashMap) Map(java.util.Map) AwaitContext(com.disney.groovity.tags.Await.AwaitContext) DeadlockFreeExecutor(com.disney.groovity.util.DeadlockFreeExecutor)

Aggregations

Execution (com.disney.groovity.stats.GroovityStatistics.Execution)1 AwaitContext (com.disney.groovity.tags.Await.AwaitContext)1 DeadlockFreeExecutor (com.disney.groovity.util.DeadlockFreeExecutor)1 ScriptHelper (com.disney.groovity.util.ScriptHelper)1 Binding (groovy.lang.Binding)1 Closure (groovy.lang.Closure)1 Script (groovy.lang.Script)1 CharArrayWriter (java.io.CharArrayWriter)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Callable (java.util.concurrent.Callable)1