Mercurial Hosting > nabble
view src/nabble/model/Executors.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children |
line wrap: on
line source
package nabble.model; import java.util.Date; import java.util.Random; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fschmidt.db.DbDatabase; import fschmidt.util.executor.RunnableWrapper; import fschmidt.util.executor.ThreadPool; import fschmidt.util.executor.ScheduledThreadPool; import fschmidt.util.executor.ThreadTimer; import fschmidt.util.java.DateUtils; public final class Executors { private Executors() {} // never private static final Logger logger = LoggerFactory.getLogger(Executors.class); public static final ThreadTimer threadTimer = new ThreadTimer(); private static final RunnableWrapper dbCleanup = new RunnableWrapper() { @Override public Runnable wrap(final Runnable command) { return new Runnable(){public void run(){ try { command.run(); } finally { fschmidt.db.pool.Pool.threadReset(); } }}; } }; private static final ScheduledThreadPool backgroundExecutor = new ScheduledThreadPool(1); static { backgroundExecutor.addRunnableWrapper(dbCleanup); backgroundExecutor.addRunnableWrapper(threadTimer); backgroundExecutor.addRunnableWrapper(new TimedExecuteWrapper()); } public static final ThreadPool foregroundExecutor = new ThreadPool(Init.get("poolSize",100)); static { foregroundExecutor.addRunnableWrapper(dbCleanup); foregroundExecutor.addRunnableWrapper(threadTimer); } private static Random rnd = new Random(); private static final long timeLimit = Init.get("execTimeLimitSeconds", 60L); private static volatile boolean isShuttingDown = false; private static long start = System.currentTimeMillis(); static void shutdown() { isShuttingDown = true; backgroundExecutor.shutdown(); foregroundExecutor.shutdown(); try { while( !backgroundExecutor.awaitTermination(1,TimeUnit.SECONDS) ) { logger.error("backgroundExecutor failed to shutdown"); for( Thread thread : backgroundExecutor.getThreads() ) { if( thread.isAlive() ) { Throwable t = new Throwable(thread.toString()); t.setStackTrace(thread.getStackTrace()); logger.error("backgroundExecutor thread",t); } } } /* why does this matter? while( !foregroundExecutor.awaitTermination(1,TimeUnit.SECONDS) ) { logger.error("foregroundExecutor failed to shutdown"); for( Thread thread : foregroundExecutor.getThreads() ) { if( thread.isAlive() ) { Throwable t = new Throwable(thread.toString()); t.setStackTrace(thread.getStackTrace()); logger.error("foregroundExecutor thread",t); } } } */ } catch(InterruptedException e) { logger.error("",e); } } public static boolean isShuttingDown() { long time = (System.currentTimeMillis() - start)/1000; if( time > timeLimit ) logger.error("exec took too long, " + time + " seconds",new Exception()); start = System.currentTimeMillis(); return isShuttingDown; } private static final class TimedExecuteWrapper implements RunnableWrapper { private ThreadLocal<Exception> trace = new ThreadLocal<Exception>() { protected Exception initialValue() { return new Exception("exec created"); } }; @Override public Runnable wrap(final Runnable command) { return new Runnable(){public void run(){ Thread.currentThread().setName("background-thread"); trace.get(); start = System.currentTimeMillis(); try { command.run(); } finally { long time = (System.currentTimeMillis() - start)/1000; if( time > timeLimit ) logger.error("exec took too long, " + time + " seconds",trace); } }}; } } public static void executeNow(Runnable command) { foregroundExecutor.execute(command); } public static void executeSometime(Runnable command) { schedule(command,0,TimeUnit.SECONDS); } public static void schedule(Runnable command,long delay,TimeUnit unit) { backgroundExecutor.schedule(command,delay,unit); } public static void scheduleWithFixedDelay(final Runnable command,long initialDelay,final long delay,final TimeUnit unit) { Runnable repeatedCommand = new Runnable(){public void run(){ command.run(); schedule(this,delay,unit); }}; schedule(repeatedCommand,initialDelay,unit); } public static void runDaily(Runnable task) { scheduleWithFixedDelay(task, rnd.nextInt(60*60*24), 60*60*24, TimeUnit.SECONDS); } private static final long MILLIS_PER_DAY = 1000L*60L*60L*24L; public static void runDaily(final Runnable task, int hour, int minute) { final long millisAfterMidnight = ((long) hour * 60 + minute) * 60 * 1000; Date now = new Date(); long time = now.getTime() - DateUtils.roundToDay(now).getTime(); long sleep = time < millisAfterMidnight ? millisAfterMidnight - time : MILLIS_PER_DAY - (time - millisAfterMidnight) ; scheduleWithFixedDelay(task, sleep/(1000L*60), 60*24, TimeUnit.MINUTES); } public static void executeAfterCommit(DbDatabase db,final Runnable command) { db.runAfterCommit(new Runnable(){public void run(){ executeNow(command); }}); } }