Stopping the execution of a Groovy script

Clueless picture Clueless · Aug 12, 2011 · Viewed 10.6k times · Source

I am embeding Groovy runtime in my code and I would like to have the ability to interrupt it. I don't have control of the scripts that are going to run. I read about groovy.transform.ThreadInterrupt to handle thread interruptions but for some reason this code below isn't working as intended. It's actually waiting 10000 ms instead of the 1000 where it should get interrupted.

Any ideas? Thank you.

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.transform.ThreadInterrupt;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;

public class GroovyTest extends Thread {
    private Binding binding;
    private GroovyShell shell;

    public GroovyTest() {
        CompilerConfiguration compilerConfig = new CompilerConfiguration();
        compilerConfig.addCompilationCustomizers(
                new ASTTransformationCustomizer(ThreadInterrupt.class));

        binding = new Binding();

        shell = new GroovyShell(this.getClass().getClassLoader(), binding, compilerConfig);
    }

    @Override
    public void run() {
        System.out.println("Started");

        shell.run("for(int i = 0; i < 10; i++) {sleep(1000)}", "test", new String[] {});

        System.out.println("Finished");
    }

    public static void main(String args[]) throws InterruptedException {
        GroovyTest test = new GroovyTest();

        test.start();

        System.out.println("Sleeping: " + System.currentTimeMillis());

        Thread.sleep(1000);

        System.out.println("Interrupting: " + System.currentTimeMillis());

        test.interrupt();
        test.join();

        System.out.println("Interrupted?: " + System.currentTimeMillis());
    }
}

Answer

Clueless picture Clueless · Aug 13, 2011

Answering my own question. Groovy's static method sleep doesn't interrupt even if you try to if there isn't a closure. Pretty weird default if you ask me. Recomended way is to call Thread.sleep(ms)

private static void sleepImpl(long millis, Closure closure) {
    long start = System.currentTimeMillis();
    long rest = millis;
    long current;
    while (rest > 0) {
        try {
            Thread.sleep(rest);
            rest = 0;
        } catch (InterruptedException e) {
            if (closure != null) {
                if (DefaultTypeTransformation.castToBoolean(closure.call(e))) {
                    return;
                }
            }
            current = System.currentTimeMillis(); // compensate for closure's time
            rest = millis + start - current;
        }
    }
}