/** we define some extra tasks to be imported into main build or shared. */ // load .env settings - mostly secrets task dotenv{ def ef=file('.env'); if(!ef.exists()) ef=file('../.env'); ef.readLines().each() { if(it.isEmpty() || it.startsWith("#")) return true; def (key,value)=it.tokenize('=') project.ext.set(key,value) } } task packageJavadoc(type: Jar, dependsOn: 'javadoc') { from javadoc archiveClassifier = 'javadoc' } task packageSources(type: Jar, dependsOn: 'classes') { from sourceSets.main.allSource archiveClassifier = 'sources' } task fat_jar(type: Jar) { archiveBaseName = 'fat-'+project.name archiveVersion = project.version duplicatesStrategy = DuplicatesStrategy.EXCLUDE /* manifest { attributes "Main-Class": mainClassName attributes "Class-Path": configurations.runtimeClasspath.collect { it.getName() }.join(' ') } */ from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }{ exclude "META-INF/NOTICE.txt" exclude "META-INF/LICENSE" } with jar } /** We define a singleton pattern using background thread to launch a blocking process. Later we make sure to terminate previous running driver threads before starting new. Also we split start, stop because we might not run in continouse mode. */ class Server implements Runnable{ static Server singleton=null; public static Server main(){ if(singleton==null) singleton=new Server(); return singleton; } //org.slf4j.Logger log=null; Thread driver=null; Runnable task=null; protected Server(){} public void info(String msg){ //if(log!=null) log.info(msg); else println(msg); println(msg); } //public Server setLogger(org.slf4j.Logger l){ // log=l; // return this; //} public Server useDriver(boolean f){ info("using driver:"+f); if(f){ driver=new Thread(this); driver.setName("server.driver"); }else{ driver=null; } return this; } public void run(){ info("running task"); try{ task.run(); }catch(java.lang.Exception ex){ info("running task:interrupted"); } } public Server start(Runnable c){ info("starting server"); this.task=c; if(driver!=null){ driver.start(); }else{ this.run(); } return this; } public Server stop(){ info("stopping server"); if(driver!=null){ driver.interrupt(); try{ driver.join(5000); // Wait up to 5 seconds for graceful shutdown }catch(InterruptedException e){ info("interrupted while waiting for driver to stop"); } } // Clean up stale threads using proper interruption for(Thread th:Thread.getAllStackTraces().keySet()){ if(th.getName().equalsIgnoreCase("executor")){ info("cleaning up stale driver:"+th.toString()) th.interrupt(); try{ th.join(2000); // Wait up to 2 seconds }catch(InterruptedException e){ // Ignore } } if(th.getName().equalsIgnoreCase("server.driver")){ info("cleaning up stale driver:"+th.toString()) th.interrupt(); try{ th.join(2000); // Wait up to 2 seconds }catch(InterruptedException e){ // Ignore } } } return this; } } task runServer{ inputs.files 'src' doFirst { boolean threaded=project.gradle.startParameter.continuous; Server.main().stop().useDriver(threaded);//.setLogger(logger); } doLast { Server.main().start({ println(application.mainClass.get()) project.javaexec { classpath = sourceSets.main.runtimeClasspath main = application.mainClass.get() } }); } }