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 }