/
InitReactorRunner.java
114 lines (100 loc) · 4.37 KB
/
InitReactorRunner.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package jenkins;
import com.google.common.collect.Lists;
import jenkins.util.SystemProperties;
import hudson.init.InitMilestone;
import hudson.init.InitReactorListener;
import hudson.util.DaemonThreadFactory;
import hudson.util.NamingThreadFactory;
import jenkins.model.Configuration;
import jenkins.model.Jenkins;
import org.jvnet.hudson.reactor.Milestone;
import org.jvnet.hudson.reactor.Reactor;
import org.jvnet.hudson.reactor.ReactorException;
import org.jvnet.hudson.reactor.ReactorListener;
import org.jvnet.hudson.reactor.Task;
import java.io.IOException;
import java.util.List;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.logging.Level.SEVERE;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* Executes the {@link Reactor} for the purpose of bootup.
*
* @author Kohsuke Kawaguchi
*/
public class InitReactorRunner {
public void run(Reactor reactor) throws InterruptedException, ReactorException, IOException {
reactor.addAll(InitMilestone.ordering().discoverTasks(reactor));
ExecutorService es;
if (Jenkins.PARALLEL_LOAD)
es = new ThreadPoolExecutor(
TWICE_CPU_NUM, TWICE_CPU_NUM, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new DaemonThreadFactory());
else
es = Executors.newSingleThreadExecutor(new NamingThreadFactory(new DaemonThreadFactory(), "InitReactorRunner"));
try {
reactor.execute(es,buildReactorListener());
} finally {
es.shutdownNow(); // upon a successful return the executor queue should be empty. Upon an exception, we want to cancel all pending tasks
}
}
/**
* Aggregates all the listeners into one and returns it.
*
* <p>
* At this point plugins are not loaded yet, so we fall back to the META-INF/services look up to discover implementations.
* As such there's no way for plugins to participate into this process.
*/
private ReactorListener buildReactorListener() throws IOException {
List<ReactorListener> r = Lists.newArrayList(ServiceLoader.load(InitReactorListener.class, Thread.currentThread().getContextClassLoader()));
r.add(new ReactorListener() {
final Level level = Level.parse( Configuration.getStringConfigParameter("initLogLevel", "FINE") );
public void onTaskStarted(Task t) {
LOGGER.log(level, "Started {0}", getDisplayName(t));
}
public void onTaskCompleted(Task t) {
LOGGER.log(level, "Completed {0}", getDisplayName(t));
}
public void onTaskFailed(Task t, Throwable err, boolean fatal) {
LOGGER.log(SEVERE, "Failed " + getDisplayName(t), err);
}
public void onAttained(Milestone milestone) {
Level lv = level;
String s = "Attained "+milestone.toString();
if (milestone instanceof InitMilestone) {
lv = Level.INFO; // noteworthy milestones --- at least while we debug problems further
onInitMilestoneAttained((InitMilestone) milestone);
s = milestone.toString();
}
LOGGER.log(lv,s);
}
});
return new ReactorListener.Aggregator(r);
}
/** Like {@link Task#getDisplayName} but more robust. */
@Restricted(NoExternalUse.class)
public static String getDisplayName(Task t) {
try {
return t.getDisplayName();
} catch (RuntimeException | Error x) {
LOGGER.log(Level.WARNING, "failed to find displayName of " + t, x);
return t.toString();
}
}
/**
* Called when the init milestone is attained.
*/
protected void onInitMilestoneAttained(InitMilestone milestone) {
}
private static final int TWICE_CPU_NUM = SystemProperties.getInteger(
InitReactorRunner.class.getName()+".concurrency",
Runtime.getRuntime().availableProcessors() * 2);
private static final Logger LOGGER = Logger.getLogger(InitReactorRunner.class.getName());
}