in core/src/main/java/hudson/model/Executor.java [320:463]
public void run() {
if (!owner.isOnline()) {
resetWorkUnit("went off-line before the task's worker thread started");
owner.removeExecutor(this);
queue.scheduleMaintenance();
return;
}
if (owner.getNode() == null) {
resetWorkUnit("was removed before the task's worker thread started");
owner.removeExecutor(this);
queue.scheduleMaintenance();
return;
}
final WorkUnit workUnit;
lock.writeLock().lock();
try {
startTime = System.currentTimeMillis();
workUnit = this.workUnit;
} finally {
lock.writeLock().unlock();
}
try (ACLContext ctx = ACL.as(ACL.SYSTEM)) {
SubTask task;
// transition from idle to building.
// perform this state change as an atomic operation wrt other queue operations
task = Queue.withLock(new java.util.concurrent.Callable<SubTask>() {
@Override
public SubTask call() throws Exception {
if (!owner.isOnline()) {
resetWorkUnit("went off-line before the task's worker thread was ready to execute");
return null;
}
if (owner.getNode() == null) {
resetWorkUnit("was removed before the task's worker thread was ready to execute");
return null;
}
// after this point we cannot unwind the assignment of the work unit, if the owner
// is removed or goes off-line then the build will just have to fail.
workUnit.setExecutor(Executor.this);
queue.onStartExecuting(Executor.this);
if (LOGGER.isLoggable(FINE))
LOGGER.log(FINE, getName()+" grabbed "+workUnit+" from queue");
SubTask task = workUnit.work;
Executable executable = task.createExecutable();
if (executable == null) {
String displayName = task instanceof Queue.Task ? ((Queue.Task) task).getFullDisplayName() : task.getDisplayName();
LOGGER.log(WARNING, "{0} cannot be run (for example because it is disabled)", displayName);
}
lock.writeLock().lock();
try {
Executor.this.executable = executable;
} finally {
lock.writeLock().unlock();
}
workUnit.setExecutable(executable);
return task;
}
});
Executable executable;
lock.readLock().lock();
try {
if (this.workUnit == null) {
// we called resetWorkUnit, so bail. Outer finally will remove this and schedule queue maintenance
return;
}
executable = this.executable;
} finally {
lock.readLock().unlock();
}
if (LOGGER.isLoggable(FINE))
LOGGER.log(FINE, getName()+" is going to execute "+executable);
Throwable problems = null;
try {
workUnit.context.synchronizeStart();
// this code handles the behavior of null Executables returned
// by tasks. In such case Jenkins starts the workUnit in order
// to report results to console outputs.
if (executable == null) {
return;
}
executableEstimatedDuration = executable.getEstimatedDuration();
if (executable instanceof Actionable) {
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.log(FINER, "when running {0} from {1} we are copying {2} actions whereas the item currently has {3}", new Object[] {executable, workUnit.context.item, workUnit.context.actions, workUnit.context.item.getAllActions()});
}
for (Action action: workUnit.context.actions) {
((Actionable) executable).addAction(action);
}
}
setName(getName() + " : executing " + executable.toString());
Authentication auth = workUnit.context.item.authenticate();
LOGGER.log(FINE, "{0} is now executing {1} as {2}", new Object[] {getName(), executable, auth});
if (LOGGER.isLoggable(FINE) && auth.equals(ACL.SYSTEM)) { // i.e., unspecified
if (QueueItemAuthenticatorDescriptor.all().isEmpty()) {
LOGGER.fine("no QueueItemAuthenticator implementations installed");
} else if (QueueItemAuthenticatorConfiguration.get().getAuthenticators().isEmpty()) {
LOGGER.fine("no QueueItemAuthenticator implementations configured");
} else {
LOGGER.log(FINE, "some QueueItemAuthenticator implementations configured but neglected to authenticate {0}", executable);
}
}
try (ACLContext context = ACL.as(auth)) {
queue.execute(executable, task);
}
} catch (AsynchronousExecution x) {
lock.writeLock().lock();
try {
x.setExecutorWithoutCompleting(this);
this.asynchronousExecution = x;
} finally {
lock.writeLock().unlock();
}
x.maybeComplete();
} catch (Throwable e) {
problems = e;
} finally {
boolean needFinish1;
lock.readLock().lock();
try {
needFinish1 = asynchronousExecution == null;
} finally {
lock.readLock().unlock();
}
if (needFinish1) {
finish1(problems);
}
}
} catch (InterruptedException e) {
LOGGER.log(FINE, getName()+" interrupted",e);
// die peacefully
} catch(Exception | Error e) {
LOGGER.log(SEVERE, getName()+": Unexpected executor death", e);
} finally {
if (asynchronousExecution == null) {
finish2();
}
}
}