All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sirius.kernel.async.TaskContext Maven / Gradle / Ivy

/*
 * Made with all the love in the world
 * by scireum in Remshalden, Germany
 *
 * Copyright by scireum GmbH
 * http://www.scireum.de - [email protected]
 */

package sirius.kernel.async;

import sirius.kernel.commons.RateLimit;
import sirius.kernel.commons.Strings;
import sirius.kernel.di.std.Part;

import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * Provides an interface between a running task and a monitoring system.
 * 

* Any task or background job can access its TaskContext using either {@link TaskContext#get()} or * {@link sirius.kernel.async.CallContext#get(Class)}. This provides an interface to a monitoring system which * might be present (by calling {@link sirius.kernel.async.TaskContext#setAdapter(TaskContextAdapter)}. If no * monitoring is available, the default mechanisms of the platform are used. */ public class TaskContext implements SubContext { /** * Forms the default value used to specify the system string which identifies the currently active module. * * @see #getSystemString() */ private static final String GENERIC = "GENERIC"; /** * One the system string is changed, it will be updated in the mapped diagnostic context (MDC) using this name. * * @see #setSystem(String) * @see #setSubSystem(String) * @see #setJob(String) */ public static final String MDC_SYSTEM = "system"; private static final int STATE_UPDATE_INTERVAL = 5; private TaskContextAdapter adapter; private String system = GENERIC; private String subSystem = GENERIC; private String job = GENERIC; private CallContext parent; private RateLimit stateUpdate = RateLimit.timeInterval(STATE_UPDATE_INTERVAL, TimeUnit.SECONDS); @Part private static Tasks tasks; /** * Generates a new TaskContext. *

* Normally this is should only be invoked by {@link CallContext}. Use {@link CallContext#get(Class)} to obtain an * instance. */ public TaskContext() { this.adapter = new BasicTaskContextAdapter(this); this.parent = CallContext.getCurrent(); } /** * Provides access to the TaskContext for the current thread. *

* This is boilerplate for {@code CallContext.getCurrent().get(TaskContext.class)} * * @return the task context for the current thread */ public static TaskContext get() { return CallContext.getCurrent().get(TaskContext.class); } /** * Writes a log message to the monitor. *

* If no monitor is available, the async logger will be used. * * @param message the message to log * @param args the parameters used to format the message (see {@link Strings#apply(String, Object...)}) */ public void log(String message, Object... args) { if (adapter != null) { adapter.log(Strings.apply(message, args)); } else { Tasks.LOG.INFO(getSystemString() + ": " + Strings.apply(message, args)); } } /** * Writes a debug message to the monitor. *

* If no monitor is available, the async logger will be used. * * @param message the message to log * @param args the parameters used to format the message (see {@link Strings#apply(String, Object...)}) */ public void trace(String message, Object... args) { adapter.trace(Strings.apply(message, args)); } /** * Logs the given message and sets it as current state. * * @param message the message to log * @param args the parameters used to format the message (see {@link Strings#apply(String, Object...)}) */ public void logAsCurrentState(String message, Object... args) { log(message, args); setState(message, args); } /** * Sets the new state of the current task. * * @param newState the message to set as state * @param args the parameters used to format the state message (see {@link Strings#apply(String, Object...)}) */ public void setState(String newState, Object... args) { adapter.setState(Strings.apply(newState, args)); } /** * Can be used to determine if the state should be refreshed. *

* By calling {@code shouldUpdateState().check()} an inner loop can detect if a state update should be * performed. This will limit the number of updates to a reasonable value. * * @return a rate limit which limits the number of updates to a reasonable value */ public RateLimit shouldUpdateState() { return stateUpdate; } /** * Signals the monitor that the execution had an error. *

* Although an error is signaled, this will not cancel or interrupt the execution of the task. This is merely * a signal for an user or administrator that an unexpected or non-anticipated event occurred. */ public void markErroneous() { adapter.markErroneous(); } /** * Determines if the execution of this task is still active. *

* A task can be either stopped via the {@link #cancel()} method or due to a system shutdown. In any case it is * wise for a task to check this flag every once in a while to keep the overall app responsive. * * @return true as long as the task is expected to be executed, false otherwise */ public boolean isActive() { return adapter.isActive() && tasks.isRunning(); } /** * Cancels the execution of this task. *

* Note that this will not kill the underlying thread. This will merely toggle the canceled flag. It is * however the task programmers job to check this flag and interrupt / terminate all computations. */ public void cancel() { adapter.cancel(); } /** * Utility to iterate through a collection while checking the cancelled flag. * * @param iterable the collection to iterate through * @param consumer the processor invoked for each element * @param the type of elements being processed */ public void iterateWhileActive(Iterable iterable, Consumer consumer) { for (T obj : iterable) { if (!isActive()) { return; } consumer.accept(obj); } } /** * Returns the System String. *

* This will consist of three parts: System, Sub-System and Job. It is used to provide information which * module is currently active. Therefore the System will provide a raw information which module is * active. This might be HTTP for the web server or the category of an executor in {@link Tasks}. *

* The Sub-System will provide a more detailed information, like the class name or the name of * a component which is currently active. *

* Finally the Job will provide a detailed information what's being currently processed. This might be * the effective URI of the request being processed by the web server or the name of a file currently being * imported. * * @return the System String with a format like System::Sub-System::Job */ public String getSystemString() { return system + "::" + subSystem + "::" + job; } /** * Returns the System component of the System String * * @return the system component of the system string * @see #getSystemString() */ public String getSystem() { return system; } /** * Sets the System component of the System String * * @param system the new system component to set * @return the task context itself for fluent method calls * @see #getSystemString() */ public TaskContext setSystem(String system) { if (Strings.isEmpty(system)) { this.system = GENERIC; } else { this.system = system; } parent.addToMDC(MDC_SYSTEM, getSystemString()); return this; } /** * Returns the Sub-System component of the System String * * @return the sub system component of the system string * @see #getSystemString() */ public String getSubSystem() { return subSystem; } /** * Sets the Sub-System component of the System String * * @param subSystem the new sub system component to set * @return the task context itself for fluent method calls * @see #getSystemString() */ public TaskContext setSubSystem(String subSystem) { if (Strings.isEmpty(subSystem)) { this.subSystem = GENERIC; } else { this.subSystem = subSystem; } parent.addToMDC(MDC_SYSTEM, getSystemString()); return this; } /** * Returns the Job component of the System String * * @return the job component of the system string * @see #getSystemString() */ public String getJob() { return job; } /** * Sets the Job component of the System String * * @param job the new job component to set * @return the task context itself for fluent method calls * @see #getSystemString() */ public TaskContext setJob(String job) { if (Strings.isEmpty(job)) { this.job = GENERIC; } else { this.job = job; } parent.addToMDC(MDC_SYSTEM, getSystemString()); return this; } @Override public String toString() { return getSystemString(); } /** * Returns the monitoring adapter which is currently active. * * @return the monitoring adapter or null if no adapter is active */ public TaskContextAdapter getAdapter() { return adapter; } /** * Installs the given adapter as monitoring adapter. * * @param adapter the adapter to install */ public void setAdapter(TaskContextAdapter adapter) { this.adapter = adapter; } @Override public SubContext fork() { TaskContext child = new TaskContext(); child.adapter = adapter; return child; } @Override public void detach() { // Nothing to do... } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy