Search in sources :

Example 1 with DeadlockFreeExecutor

use of com.disney.groovity.util.DeadlockFreeExecutor 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)

Example 2 with DeadlockFreeExecutor

use of com.disney.groovity.util.DeadlockFreeExecutor in project groovity by disney.

the class Await method tag.

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object tag(final 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 awaitContext = AwaitContext.create(variables);
    DeadlockFreeExecutor createdThreadPool = null;
    DeadlockFreeExecutor oldThreadPool = null;
    if (!variables.containsKey(Async.EXECUTOR_BINDING)) {
        Integer numThreads = resolve(attributes, POOL, Integer.class);
        if (numThreads != null) {
            createdThreadPool = new DeadlockFreeExecutor(interruptFactory, numThreads);
            oldThreadPool = (DeadlockFreeExecutor) variables.put(Async.EXECUTOR_BINDING, createdThreadPool);
        }
    }
    final Writer origOut = (Writer) variables.get(OUT);
    try {
        Collection<Object> resultsList;
        final long timeoutTime = timeoutSeconds == null ? -1 : System.currentTimeMillis() + (timeoutSeconds * 1000);
        Throwable error = null;
        try {
            body.call();
        } catch (Throwable e) {
            error = e;
        }
        ArrayDeque<Future> futuresList = awaitContext.getFutures();
        resultsList = new ArrayList<>(futuresList.size());
        for (Future f : futuresList) {
            if (error != null) {
                f.cancel(true);
                continue;
            }
            // flush any pending writers before waiting
            Optional<CharArrayWriter> ocw;
            while ((ocw = awaitContext.nextFragmentWriter()).isPresent()) {
                CharArrayWriter cw = ocw.get();
                if (cw.size() > 0 && origOut != null) {
                    cw.writeTo(origOut);
                }
            }
            if (timeoutTime == -1 || f.isDone()) {
                try {
                    resultsList.add(f.get());
                } catch (Throwable e) {
                    error = e;
                }
            } else {
                long timeoutDelta = timeoutTime - System.currentTimeMillis();
                if (timeoutDelta <= 0) {
                    error = new InterruptedException("Await reached timeout of " + timeoutSeconds);
                    f.cancel(true);
                } else {
                    try {
                        resultsList.add(f.get(timeoutDelta, TimeUnit.MILLISECONDS));
                    } catch (Throwable e) {
                        error = e;
                    }
                }
            }
            if (error == null) {
                // flush async buffer
                CharArrayWriter cw = awaitContext.nextFragmentWriter().get();
                if (cw.size() > 0 && origOut != null) {
                    cw.writeTo(origOut);
                }
            }
        }
        if (error != null) {
            if (error instanceof Exception) {
                throw (Exception) error;
            }
            throw new ExecutionException(error);
        }
        if (origOut != null) {
            final Object finalOut = variables.get(OUT);
            if (finalOut != origOut) {
                final CharArrayWriter cfo = ((CharArrayWriter) finalOut);
                try {
                    if (cfo.size() > 0) {
                        cfo.writeTo(origOut);
                    }
                } finally {
                    cfo.close();
                }
            }
        }
        final String var = resolve(attributes, VAR, String.class);
        if (var != null && var.length() > 0) {
            variables.put(var, resultsList);
        }
        return resultsList;
    } finally {
        awaitContext.close(variables);
        if (origOut != null) {
            variables.put(OUT, origOut);
        } else {
            variables.remove(OUT);
        }
        if (createdThreadPool != null) {
            createdThreadPool.shutdown();
            try {
                if (!createdThreadPool.awaitTermination(60, TimeUnit.SECONDS)) {
                    createdThreadPool.shutdownNow();
                    createdThreadPool.awaitTermination(60, TimeUnit.SECONDS);
                }
            } catch (InterruptedException e) {
                createdThreadPool.shutdownNow();
            }
            if (oldThreadPool != null) {
                variables.put(Async.EXECUTOR_BINDING, oldThreadPool);
            } else {
                variables.remove(Async.EXECUTOR_BINDING);
            }
        }
    }
}
Also used : Binding(groovy.lang.Binding) CharArrayWriter(java.io.CharArrayWriter) ExecutionException(java.util.concurrent.ExecutionException) Future(java.util.concurrent.Future) ScriptHelper(com.disney.groovity.util.ScriptHelper) ExecutionException(java.util.concurrent.ExecutionException) Map(java.util.Map) DeadlockFreeExecutor(com.disney.groovity.util.DeadlockFreeExecutor) CharArrayWriter(java.io.CharArrayWriter) Writer(java.io.Writer)

Aggregations

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