Mercurial Hosting > nabble
comparison 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 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:7ecd1a4ef557 |
|---|---|
| 1 package nabble.model; | |
| 2 | |
| 3 import java.util.Date; | |
| 4 import java.util.Random; | |
| 5 import java.util.concurrent.TimeUnit; | |
| 6 import org.slf4j.Logger; | |
| 7 import org.slf4j.LoggerFactory; | |
| 8 import fschmidt.db.DbDatabase; | |
| 9 import fschmidt.util.executor.RunnableWrapper; | |
| 10 import fschmidt.util.executor.ThreadPool; | |
| 11 import fschmidt.util.executor.ScheduledThreadPool; | |
| 12 import fschmidt.util.executor.ThreadTimer; | |
| 13 import fschmidt.util.java.DateUtils; | |
| 14 | |
| 15 | |
| 16 public final class Executors { | |
| 17 private Executors() {} // never | |
| 18 | |
| 19 private static final Logger logger = LoggerFactory.getLogger(Executors.class); | |
| 20 | |
| 21 public static final ThreadTimer threadTimer = new ThreadTimer(); | |
| 22 | |
| 23 private static final RunnableWrapper dbCleanup = new RunnableWrapper() { | |
| 24 @Override public Runnable wrap(final Runnable command) { | |
| 25 return new Runnable(){public void run(){ | |
| 26 try { | |
| 27 command.run(); | |
| 28 } finally { | |
| 29 fschmidt.db.pool.Pool.threadReset(); | |
| 30 } | |
| 31 }}; | |
| 32 } | |
| 33 }; | |
| 34 | |
| 35 private static final ScheduledThreadPool backgroundExecutor = new ScheduledThreadPool(1); | |
| 36 static { | |
| 37 backgroundExecutor.addRunnableWrapper(dbCleanup); | |
| 38 backgroundExecutor.addRunnableWrapper(threadTimer); | |
| 39 backgroundExecutor.addRunnableWrapper(new TimedExecuteWrapper()); | |
| 40 } | |
| 41 public static final ThreadPool foregroundExecutor = new ThreadPool(Init.get("poolSize",100)); | |
| 42 static { | |
| 43 foregroundExecutor.addRunnableWrapper(dbCleanup); | |
| 44 foregroundExecutor.addRunnableWrapper(threadTimer); | |
| 45 } | |
| 46 private static Random rnd = new Random(); | |
| 47 | |
| 48 private static final long timeLimit = Init.get("execTimeLimitSeconds", 60L); | |
| 49 private static volatile boolean isShuttingDown = false; | |
| 50 private static long start = System.currentTimeMillis(); | |
| 51 | |
| 52 static void shutdown() { | |
| 53 isShuttingDown = true; | |
| 54 backgroundExecutor.shutdown(); | |
| 55 foregroundExecutor.shutdown(); | |
| 56 try { | |
| 57 while( !backgroundExecutor.awaitTermination(1,TimeUnit.SECONDS) ) { | |
| 58 logger.error("backgroundExecutor failed to shutdown"); | |
| 59 for( Thread thread : backgroundExecutor.getThreads() ) { | |
| 60 if( thread.isAlive() ) { | |
| 61 Throwable t = new Throwable(thread.toString()); | |
| 62 t.setStackTrace(thread.getStackTrace()); | |
| 63 logger.error("backgroundExecutor thread",t); | |
| 64 } | |
| 65 } | |
| 66 } | |
| 67 /* why does this matter? | |
| 68 while( !foregroundExecutor.awaitTermination(1,TimeUnit.SECONDS) ) { | |
| 69 logger.error("foregroundExecutor failed to shutdown"); | |
| 70 for( Thread thread : foregroundExecutor.getThreads() ) { | |
| 71 if( thread.isAlive() ) { | |
| 72 Throwable t = new Throwable(thread.toString()); | |
| 73 t.setStackTrace(thread.getStackTrace()); | |
| 74 logger.error("foregroundExecutor thread",t); | |
| 75 } | |
| 76 } | |
| 77 } | |
| 78 */ | |
| 79 } catch(InterruptedException e) { | |
| 80 logger.error("",e); | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 public static boolean isShuttingDown() { | |
| 85 long time = (System.currentTimeMillis() - start)/1000; | |
| 86 if( time > timeLimit ) | |
| 87 logger.error("exec took too long, " + time + " seconds",new Exception()); | |
| 88 start = System.currentTimeMillis(); | |
| 89 return isShuttingDown; | |
| 90 } | |
| 91 | |
| 92 private static final class TimedExecuteWrapper implements RunnableWrapper { | |
| 93 private ThreadLocal<Exception> trace = new ThreadLocal<Exception>() { | |
| 94 protected Exception initialValue() { | |
| 95 return new Exception("exec created"); | |
| 96 } | |
| 97 }; | |
| 98 | |
| 99 @Override public Runnable wrap(final Runnable command) { | |
| 100 return new Runnable(){public void run(){ | |
| 101 Thread.currentThread().setName("background-thread"); | |
| 102 trace.get(); | |
| 103 start = System.currentTimeMillis(); | |
| 104 try { | |
| 105 command.run(); | |
| 106 } finally { | |
| 107 long time = (System.currentTimeMillis() - start)/1000; | |
| 108 if( time > timeLimit ) | |
| 109 logger.error("exec took too long, " + time + " seconds",trace); | |
| 110 } | |
| 111 }}; | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 public static void executeNow(Runnable command) { | |
| 116 foregroundExecutor.execute(command); | |
| 117 } | |
| 118 | |
| 119 | |
| 120 | |
| 121 public static void executeSometime(Runnable command) { | |
| 122 schedule(command,0,TimeUnit.SECONDS); | |
| 123 } | |
| 124 | |
| 125 public static void schedule(Runnable command,long delay,TimeUnit unit) { | |
| 126 backgroundExecutor.schedule(command,delay,unit); | |
| 127 } | |
| 128 | |
| 129 public static void scheduleWithFixedDelay(final Runnable command,long initialDelay,final long delay,final TimeUnit unit) { | |
| 130 Runnable repeatedCommand = new Runnable(){public void run(){ | |
| 131 command.run(); | |
| 132 schedule(this,delay,unit); | |
| 133 }}; | |
| 134 schedule(repeatedCommand,initialDelay,unit); | |
| 135 } | |
| 136 | |
| 137 public static void runDaily(Runnable task) { | |
| 138 scheduleWithFixedDelay(task, rnd.nextInt(60*60*24), 60*60*24, TimeUnit.SECONDS); | |
| 139 } | |
| 140 | |
| 141 private static final long MILLIS_PER_DAY = 1000L*60L*60L*24L; | |
| 142 | |
| 143 public static void runDaily(final Runnable task, int hour, int minute) { | |
| 144 final long millisAfterMidnight = ((long) hour * 60 + minute) * 60 * 1000; | |
| 145 Date now = new Date(); | |
| 146 long time = now.getTime() - DateUtils.roundToDay(now).getTime(); | |
| 147 long sleep = time < millisAfterMidnight | |
| 148 ? millisAfterMidnight - time | |
| 149 : MILLIS_PER_DAY - (time - millisAfterMidnight) | |
| 150 ; | |
| 151 scheduleWithFixedDelay(task, sleep/(1000L*60), 60*24, TimeUnit.MINUTES); | |
| 152 } | |
| 153 | |
| 154 public static void executeAfterCommit(DbDatabase db,final Runnable command) { | |
| 155 db.runAfterCommit(new Runnable(){public void run(){ | |
| 156 executeNow(command); | |
| 157 }}); | |
| 158 } | |
| 159 | |
| 160 } |
