/** causes failures in subtasks of the current task not to fail the parent; * no-op if not in a {@link TaskQueueingContext}. * <p> * essentially like a {@link #markInessential()} on all tasks in the current * {@link TaskQueueingContext}, including tasks queued subsequently */ @Beta public static void swallowChildrenFailures() { Preconditions.checkNotNull(DynamicTasks.getTaskQueuingContext(), "Task queueing context required here"); TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext(); if (qc!=null) { qc.swallowChildrenFailures(); } }
/** Calls {@link TaskQueueingContext#drain(Duration, boolean, boolean)} on the current task context */ public static TaskQueueingContext drain(Duration optionalTimeout, boolean throwFirstError) { TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext(); Preconditions.checkNotNull(qc, "Cannot drain when there is no queueing context"); qc.drain(optionalTimeout, false, throwFirstError); return qc; }
/** as {@link Tasks#swallowChildrenFailures()} but requiring a {@link TaskQueueingContext}. */ @Beta public static void swallowChildrenFailures() { Preconditions.checkNotNull(DynamicTasks.getTaskQueuingContext(), "Task queueing context required here"); Tasks.swallowChildrenFailures(); }
/** As {@link #drain(Duration, boolean)} waiting forever and throwing the first error * (excluding errors in inessential tasks), * then returning the last task in the queue (which is guaranteed to have finished without error, * if this method returns without throwing) */ public static Task<?> waitForLast() { drain(null, true); // this call to last is safe, as the above guarantees everything will have run // (on errors the above will throw so we won't come here) List<Task<?>> q = DynamicTasks.getTaskQueuingContext().getQueue(); return q.isEmpty() ? null : Iterables.getLast(q); }
/** * Tries to add the task to the current addition context if there is one, otherwise does nothing. * <p/> * Call {@link TaskQueueingResult#orSubmitAsync() orSubmitAsync()} on the returned * {@link TaskQueueingResult TaskQueueingResult} to handle execution of tasks in a * {@link BasicExecutionContext}. */ public static <T> TaskQueueingResult<T> queueIfPossible(TaskAdaptable<T> task) { TaskQueueingContext adder = getTaskQueuingContext(); boolean result = false; if (adder!=null) result = Tasks.tryQueueing(adder, task); return new TaskQueueingResult<T>(task, result); }
/** Returns the result of the last task queued in this context, coerced to the given type */ protected <V> V last(Class<V> type) { Task<?> last = waitForLast(); if (last==null) throw new IllegalStateException("No last task available (in "+DynamicTasks.getTaskQueuingContext()+")"); if (!Tasks.isQueuedOrSubmitted(last)) throw new IllegalStateException("Last task "+last+" has not been queued or submitted; will not block on its result"); return TypeCoercions.coerce(last.getUnchecked(), type); } }
public int execute() { if (DynamicTasks.getTaskQueuingContext()!=null) { return queue().getUnchecked(); } else { return executeInternal(); } }
public int execute() { if (DynamicTasks.getTaskQueuingContext()!=null) { return queue().getUnchecked(); } else { return executeInternal(); } }
protected <T> Task<T> runAtEntity(Entity entity, TaskAdaptable<T> task) { getExecutionContext(entity).submit(task); if (DynamicTasks.getTaskQueuingContext()!=null) { // put it in the queueing context so it appears in the GUI // mark it inessential as this is being invoked from code, // the caller will do 'get' to handle errors TaskTags.markInessential(task); DynamicTasks.getTaskQueuingContext().queue(task.asTask()); } return task.asTask(); }
/** * Queues the given task. * <p/> * This method is only valid within a dynamic task. Use {@link #queueIfPossible(TaskAdaptable)} * and {@link TaskQueueingResult#orSubmitAsync()} if the calling context is a basic task. * * @param task The task to queue * @throws IllegalStateException if no task queueing context is available * @return The queued task */ public static <V extends TaskAdaptable<?>> V queue(V task) { try { Preconditions.checkNotNull(task, "Task to queue cannot be null"); Preconditions.checkState(!Tasks.isQueued(task), "Task to queue must not yet be queued: %s", task); TaskQueueingContext adder = getTaskQueuingContext(); if (adder==null) { throw new IllegalStateException("Task "+task+" cannot be queued here; no queueing context available"); } adder.queue(task.asTask()); return task; } catch (Throwable e) { log.warn("Error queueing "+task+" (rethrowing): "+e); throw Exceptions.propagate(e); } }
Preconditions.checkState(!Tasks.isQueuedOrSubmitted(task), "Task to queue must not yet be submitted: {}", task); TaskQueueingContext adder = getTaskQueuingContext(); if (adder!=null) { if (Tasks.tryQueueing(adder, task)) {
/** marks the current task inessential; this mainly matters if the task is running in a parent * {@link TaskQueueingContext} and we don't want the parent to fail if this task fails * <p> * no-op (silently ignored) if not in a task */ public static void markInessential() { Task<?> task = Tasks.current(); if (task==null) { TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext(); if (qc!=null) task = qc.asTask(); } if (task!=null) { TaskTags.markInessential(task); } }
/** queues the task if needed, i.e. if it is not yet submitted (so it will run), * or if it is submitted but not queued and we are in a queueing context (so it is available for informational purposes) */ public static <T extends TaskAdaptable<?>> T queueIfNeeded(T task) { if (!Tasks.isQueued(task)) { if (Tasks.isSubmitted(task) && getTaskQueuingContext()==null) { // already submitted and not in a queueing context, don't try to queue } else { // needs submitting, put it in the queue // (will throw an error if we are not a queueing context) queue(task); } } return task; }
/** * Stops the entity and its children. * <p/> * Subclasses should override {@link #doStop} to customise behaviour. */ @Override public final void stop() { if (DynamicTasks.getTaskQueuingContext() != null) { doStop(); } else { Task<?> task = Tasks.builder().displayName("stop").body(new Runnable() { @Override public void run() { doStop(); } }).build(); Entities.submit(this, task).getUnchecked(); } }
/** * Restarts the entity and its children. * <p/> * Subclasses should override {@link #doRestart(ConfigBag)} to customise behaviour. */ @Override public final void restart() { if (DynamicTasks.getTaskQueuingContext() != null) { doRestart(ConfigBag.EMPTY); } else { Task<?> task = Tasks.builder().displayName("restart").body(new Runnable() { @Override public void run() { doRestart(ConfigBag.EMPTY); } }).build(); Entities.submit(this, task).getUnchecked(); } }
/** * Starts the entity and its children in the given locations. * <p/> * Subclasses should override {@link #doStart} to customise behaviour. */ @Override public final void start(Collection<? extends Location> locsO) { addLocations(locsO); final Collection<? extends Location> locations = Locations.getLocationsCheckingAncestors(locsO, this); checkNotNull(locations, "locations"); if (DynamicTasks.getTaskQueuingContext() != null) { doStart(locations); } else { Task<?> task = Tasks.builder().displayName("start").body(new Runnable() { @Override public void run() { doStart(locations); } }).build(); Entities.submit(this, task).getUnchecked(); } }
public static <T> Task<T> invokeEffector(Entity callingEntity, Entity entityToCall, final Effector<T> effector, final Map<String,?> parameters) { Task<T> t = Effectors.invocation(entityToCall, effector, parameters).asTask(); TaskTags.markInessential(t); // we pass to callingEntity for consistency above, but in exec-context it should be re-dispatched to targetEntity // reassign t as the return value may be a wrapper, if it is switching execution contexts; see submitInternal's javadoc t = ((EntityInternal)callingEntity).getExecutionContext().submit( MutableMap.of("tag", BrooklynTaskTags.tagForCallerEntity(callingEntity)), t); if (DynamicTasks.getTaskQueuingContext()!=null) { // include it as a child (in the gui), marked inessential, because the caller is invoking programmatically DynamicTasks.queue(t); } return t; }
/** * If custom behaviour is required by sub-classes, consider overriding {@link #preStart()} or {@link #postStart()})}. * Also consider adding additional work via tasks, executed using {@link DynamicTasks#queue(String, Callable)}. */ @Override public final void start(final Collection<? extends Location> locations) { if (DynamicTasks.getTaskQueuingContext() != null) { getLifecycleEffectorTasks().start(locations); } else { Task<?> task = Tasks.builder().displayName("start (sequential)").body(new Runnable() { @Override public void run() { getLifecycleEffectorTasks().start(locations); } }).build(); Entities.submit(this, task).getUnchecked(); } }
/** * If custom behaviour is required by sub-classes, consider overriding {@link #preRestart()} or {@link #postRestart()}. * Also consider adding additional work via tasks, executed using {@link DynamicTasks#queue(String, Callable)}. */ @Override public final void restart() { if (DynamicTasks.getTaskQueuingContext() != null) { getLifecycleEffectorTasks().restart(ConfigBag.EMPTY); } else { Task<?> task = Tasks.builder().displayName("restart").body(new Runnable() { @Override public void run() { getLifecycleEffectorTasks().restart(ConfigBag.EMPTY); } }).build(); Entities.submit(this, task).getUnchecked(); } }
/** * If custom behaviour is required by sub-classes, consider overriding {@link #preStop()} or {@link #postStop()}. * Also consider adding additional work via tasks, executed using {@link DynamicTasks#queue(String, Callable)}. */ @Override public final void stop() { // TODO There is a race where we set SERVICE_UP=false while sensor-adapter threads may still be polling. // The other thread might reset SERVICE_UP to true immediately after we set it to false here. // Deactivating adapters before setting SERVICE_UP reduces the race, and it is reduced further by setting // SERVICE_UP to false at the end of stop as well. // Perhaps we should wait until all feeds have completed here, // or do a SERVICE_STATE check before setting SERVICE_UP to true in a feed (?). if (DynamicTasks.getTaskQueuingContext() != null) { getLifecycleEffectorTasks().stop(ConfigBag.EMPTY); } else { Task<?> task = Tasks.builder().displayName("stop").body(new Runnable() { @Override public void run() { getLifecycleEffectorTasks().stop(ConfigBag.EMPTY); } }).build(); Entities.submit(this, task).getUnchecked(); } }