use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class CheEnvironmentEngine method start.
/**
* Starts provided environment.
*
* <p>Environment starts if and only all machines in environment definition start successfully.<br/>
* Otherwise exception is thrown by this method.<br/>
* It is not defined whether environment start fails right after first failure or in the end of the process.<br/>
* Starting order of machines is not guarantied. Machines can start sequentially or in parallel.
*
* @param workspaceId
* ID of workspace that owns provided environment
* @param envName
* name of environment
* @param env
* environment to start
* @param recover
* whether machines from environment should be recovered or not
* @param messageConsumer
* consumer of log messages from machines in the environment
* @param startedHandler
* handler for started machines
* @return list of running machines of this environment
* @throws ServerException
* if other error occurs
*/
public List<Instance> start(String workspaceId, String envName, Environment env, boolean recover, MessageConsumer<MachineLogMessage> messageConsumer, MachineStartedHandler startedHandler) throws ServerException, EnvironmentException, ConflictException {
EnvironmentImpl environment = new EnvironmentImpl(env);
// TODO move to machines provider
// add random chars to ensure that old environments that weren't removed by some reason won't prevent start
String networkId = NameGenerator.generate(workspaceId + "_", 16);
String namespace = EnvironmentContext.getCurrent().getSubject().getUserName();
initializeEnvironment(namespace, workspaceId, envName, environment, networkId, messageConsumer);
String devMachineName = getDevMachineName(environment);
if (devMachineName == null) {
throw new ServerException("Agent 'org.eclipse.che.ws-agent' is not found in any of environment machines");
}
startEnvironmentQueue(namespace, workspaceId, devMachineName, networkId, recover, startedHandler);
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.writeLock(workspaceId)) {
EnvironmentHolder environmentHolder = environments.get(workspaceId);
// possible only if environment was stopped during its start
if (environmentHolder == null) {
throw new ServerException("Environment start was interrupted by environment stopping");
}
environmentHolder.status = EnvStatus.RUNNING;
// prevent list modification
return new ArrayList<>(environmentHolder.machines);
}
}
use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class WorkspaceRuntimes method shutdown.
/**
* Terminates workspace runtimes service, so no more workspaces are allowed to start
* or to be stopped directly, all the running workspaces are going to be stopped,
* all the starting tasks will be eventually interrupted.
*
* @throws IllegalStateException
* if component shutdown is already called
*/
public void shutdown() throws InterruptedException {
if (!isShutdown.compareAndSet(false, true)) {
throw new IllegalStateException("Workspace runtimes service shutdown has been already called");
}
List<String> idsToStop;
try (@SuppressWarnings("unused") Unlocker u = locks.writeAllLock()) {
idsToStop = states.entrySet().stream().filter(e -> e.getValue().status != WorkspaceStatus.STOPPING).map(Map.Entry::getKey).collect(Collectors.toList());
states.clear();
}
if (!idsToStop.isEmpty()) {
LOG.info("Shutdown running environments, environments to stop: '{}'", idsToStop.size());
ExecutorService executor = Executors.newFixedThreadPool(2 * Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setNameFormat("StopEnvironmentsPool-%d").setDaemon(false).build());
for (String id : idsToStop) {
executor.execute(() -> {
try {
envEngine.stop(id);
} catch (EnvironmentNotRunningException ignored) {
// might be already stopped
} catch (Exception x) {
LOG.error(x.getMessage(), x);
}
});
}
executor.shutdown();
try {
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
executor.shutdownNow();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
LOG.error("Unable to stop runtimes termination pool");
}
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class WorkspaceRuntimes method injectRuntime.
/**
* Injects runtime information such as status and {@link WorkspaceRuntimeImpl}
* into the workspace object, if the workspace doesn't have runtime sets the
* status to {@link WorkspaceStatus#STOPPED}.
*
* @param workspace
* the workspace to inject runtime into
*/
public void injectRuntime(WorkspaceImpl workspace) {
requireNonNull(workspace, "Required non-null workspace");
RuntimeState state = null;
try (@SuppressWarnings("unused") Unlocker u = locks.readLock(workspace.getId())) {
if (states.containsKey(workspace.getId())) {
state = new RuntimeState(states.get(workspace.getId()));
}
}
if (state == null) {
workspace.setStatus(WorkspaceStatus.STOPPED);
} else {
workspace.setStatus(state.status);
try {
workspace.setRuntime(new WorkspaceRuntimeImpl(state.envName, envEngine.getMachines(workspace.getId())));
} catch (Exception x) {
workspace.setRuntime(new WorkspaceRuntimeImpl(state.envName, Collections.emptyList()));
}
}
}
use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class WorkspaceRuntimes method startAsync.
/**
* Asynchronously starts the environment of the workspace.
* Before executing start task checks whether all conditions
* are met and throws appropriate exceptions if not, so
* there is no way to start the same workspace twice.
*
* <p>Note that cancellation of resulting future won't
* interrupt workspace start, call {@link #stop(String)} directly instead.
*
* <p>If starting process is interrupted let's say within call
* to {@link #stop(String)} method, resulting future will
* be exceptionally completed(eventually) with an instance of
* {@link EnvironmentStartInterruptedException}. Note that clients
* don't have to cleanup runtime resources, the component
* will do necessary cleanup when interrupted.
*
* <p>Implementation notes:
* if thread which executes the task is interrupted, then the
* task is also eventually(depends on the environment engine implementation)
* interrupted as if {@link #stop(String)} is called directly.
* That helps to shutdown gracefully when thread pool is asked
* to {@link ExecutorService#shutdownNow()} and also reduces
* shutdown time when there are starting workspaces.
*
* @param workspace
* workspace containing target environment
* @param envName
* the name of the environment to start
* @param recover
* whether to recover from the snapshot
* @return completable future describing the instance of running environment
* @throws ConflictException
* when the workspace is already started
* @throws ConflictException
* when workspaces start refused {@link #refuseWorkspacesStart()} was called
* @throws ServerException
* when any other error occurs
* @throws IllegalArgumentException
* when the workspace doesn't contain the environment
* @throws NullPointerException
* when either {@code workspace} or {@code envName} is null
*/
public CompletableFuture<WorkspaceRuntimeImpl> startAsync(Workspace workspace, String envName, boolean recover) throws ConflictException, ServerException {
requireNonNull(workspace, "Non-null workspace required");
requireNonNull(envName, "Non-null environment name required");
EnvironmentImpl environment = copyEnv(workspace, envName);
String workspaceId = workspace.getId();
CompletableFuture<WorkspaceRuntimeImpl> cmpFuture;
StartTask startTask;
try (@SuppressWarnings("unused") Unlocker u = locks.writeLock(workspaceId)) {
checkIsNotTerminated("start the workspace");
if (isStartRefused.get()) {
throw new ConflictException(format("Start of the workspace '%s' is rejected by the system, " + "no more workspaces are allowed to start", workspace.getConfig().getName()));
}
RuntimeState state = states.get(workspaceId);
if (state != null) {
throw new ConflictException(format("Could not start workspace '%s' because its status is '%s'", workspace.getConfig().getName(), state.status));
}
startTask = new StartTask(workspaceId, envName, environment, recover, cmpFuture = new CompletableFuture<>());
states.put(workspaceId, new RuntimeState(WorkspaceStatus.STARTING, envName, startTask, sharedPool.submit(startTask)));
}
// publish event synchronously as the task may not be executed by
// executors service(due to legal cancellation), clients still have
// to receive STOPPED -> STARTING event
eventsService.publish(DtoFactory.newDto(WorkspaceStatusEvent.class).withWorkspaceId(workspaceId).withStatus(WorkspaceStatus.STARTING).withEventType(EventType.STARTING).withPrevStatus(WorkspaceStatus.STOPPED));
// so the start thread is free to go and start the environment
startTask.unlockStart();
return cmpFuture;
}
use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class WorkspaceRuntimes method getRuntime.
/**
* Gets workspace runtime descriptor.
*
* @param workspaceId
* the id of the workspace to get its runtime
* @return descriptor which describes current state of the workspace runtime
* @throws NotFoundException
* when workspace with given {@code workspaceId} is not found
* @throws ServerException
* if any error occurs while getting machines runtime information
*/
public WorkspaceRuntimeImpl getRuntime(String workspaceId) throws NotFoundException, ServerException {
requireNonNull(workspaceId, "Required non-null workspace id");
RuntimeState state;
try (@SuppressWarnings("unused") Unlocker u = locks.readLock(workspaceId)) {
state = new RuntimeState(getExistingState(workspaceId));
}
return new WorkspaceRuntimeImpl(state.envName, envEngine.getMachines(workspaceId));
}
Aggregations