[New] Extending execution policies for warning task

This commit is contained in:
Robert von Burg 2022-10-11 15:53:50 +02:00
parent 7f3bfd8fac
commit 0ce29fb2a1
Signed by: eitch
GPG Key ID: 75DB9C85C74331F7
4 changed files with 142 additions and 38 deletions

View File

@ -1,9 +1,13 @@
package li.strolch.execution; package li.strolch.execution;
import java.time.Duration;
import java.util.concurrent.ScheduledFuture;
import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.ComponentContainer;
import li.strolch.execution.policy.ExecutionPolicy; import li.strolch.execution.policy.ExecutionPolicy;
import li.strolch.model.Locator; import li.strolch.model.Locator;
import li.strolch.model.activity.Action; import li.strolch.model.activity.Action;
import li.strolch.utils.time.PeriodDuration;
/** /**
* A decoupling of {@link ExecutionPolicy ExecutionPolicies} so that the execution can be performed after a certain * A decoupling of {@link ExecutionPolicy ExecutionPolicies} so that the execution can be performed after a certain
@ -14,6 +18,26 @@ import li.strolch.model.activity.Action;
*/ */
public interface DelayedExecutionTimer { public interface DelayedExecutionTimer {
/**
* Delays the execution of the given {@link Runnable} by the given {@link PeriodDuration}
*
* @param duration
* the duration before calling the {@link Runnable}
* @param runnable
* the action to call after the given delay
*/
ScheduledFuture<?> delay(PeriodDuration duration, Runnable runnable);
/**
* Delays the execution of the given {@link Runnable} by the given {@link Duration}
*
* @param duration
* the duration before calling the {@link Runnable}
* @param runnable
* the action to call after the given delay
*/
ScheduledFuture<?> delay(Duration duration, Runnable runnable);
/** /**
* Delays the execution of the given {@link Runnable} by the given milliseconds * Delays the execution of the given {@link Runnable} by the given milliseconds
* *
@ -22,7 +46,7 @@ public interface DelayedExecutionTimer {
* @param runnable * @param runnable
* the action to call after the given delay * the action to call after the given delay
*/ */
void delay(long duration, Runnable runnable); ScheduledFuture<?> delay(long duration, Runnable runnable);
/** /**
* Completes the execution of the given {@link Action} {@link Locator} after the given duration in milliseconds * Completes the execution of the given {@link Action} {@link Locator} after the given duration in milliseconds

View File

@ -2,6 +2,7 @@ package li.strolch.execution;
import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT; import static li.strolch.runtime.StrolchConstants.SYSTEM_USER_AGENT;
import java.time.Duration;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -17,6 +18,7 @@ import li.strolch.model.Locator;
import li.strolch.model.log.LogMessage; import li.strolch.model.log.LogMessage;
import li.strolch.model.log.LogMessageState; import li.strolch.model.log.LogMessageState;
import li.strolch.model.log.LogSeverity; import li.strolch.model.log.LogSeverity;
import li.strolch.utils.time.PeriodDuration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -49,8 +51,18 @@ public class SimpleDurationExecutionTimer implements DelayedExecutionTimer {
} }
@Override @Override
public void delay(long duration, Runnable runnable) { public ScheduledFuture<?> delay(PeriodDuration duration, Runnable runnable) {
getExecutor().schedule(runnable, duration, TimeUnit.MILLISECONDS); return delay(duration.toMillis(), runnable);
}
@Override
public ScheduledFuture<?> delay(Duration duration, Runnable runnable) {
return delay(duration.toMillis(), runnable);
}
@Override
public ScheduledFuture<?> delay(long duration, Runnable runnable) {
return getExecutor().schedule(runnable, duration, TimeUnit.MILLISECONDS);
} }
@Override @Override
@ -93,8 +105,9 @@ public class SimpleDurationExecutionTimer implements DelayedExecutionTimer {
logger.error("Failed to set " + locator + " to executed due to " + e.getMessage(), e); logger.error("Failed to set " + locator + " to executed due to " + e.getMessage(), e);
if (this.agent.getContainer().hasComponent(OperationsLog.class)) { if (this.agent.getContainer().hasComponent(OperationsLog.class)) {
this.agent.getContainer().getComponent(OperationsLog.class).addMessage( this.agent.getContainer()
new LogMessage(realm, SYSTEM_USER_AGENT, locator, LogSeverity.Exception, .getComponent(OperationsLog.class)
.addMessage(new LogMessage(realm, SYSTEM_USER_AGENT, locator, LogSeverity.Exception,
LogMessageState.Information, ResourceBundle.getBundle("strolch-service"), LogMessageState.Information, ResourceBundle.getBundle("strolch-service"),
"execution.handler.failed.executed").withException(e).value("reason", e)); "execution.handler.failed.executed").withException(e).value("reason", e));
} }

View File

@ -16,6 +16,7 @@ import li.strolch.execution.Controller;
import li.strolch.execution.DelayedExecutionTimer; import li.strolch.execution.DelayedExecutionTimer;
import li.strolch.execution.ExecutionHandler; import li.strolch.execution.ExecutionHandler;
import li.strolch.model.Locator; import li.strolch.model.Locator;
import li.strolch.model.Resource;
import li.strolch.model.State; import li.strolch.model.State;
import li.strolch.model.activity.Action; import li.strolch.model.activity.Action;
import li.strolch.model.activity.Activity; import li.strolch.model.activity.Activity;
@ -50,6 +51,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
protected String realm; protected String realm;
protected String actionType; protected String actionType;
protected Locator resourceLoc;
protected Locator actionLoc; protected Locator actionLoc;
/** /**
@ -65,7 +67,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
} }
/** /**
* <p>Set the {@link Controller} for this execution policy. Usually called by the controller itself, when instantiating this instance</p> * <p>Set the {@link Controller} for this execution policy. Usually called by the controller itself, when
* instantiating this instance</p>
* *
* <p><b>Note:</b> This is used as execution policies can have a longer lifecycle than its transaction.</p> * <p><b>Note:</b> This is used as execution policies can have a longer lifecycle than its transaction.</p>
* *
@ -89,6 +92,22 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
return this.controller; return this.controller;
} }
/**
* Returns the type of the {@link Resource} for this action. Can only be called after {@link #initialize(Action)}
* was called.
*/
protected String getResourceType() {
return this.resourceLoc.get(1);
}
/**
* Returns the id of the {@link Resource} for this action. Can only be called after {@link #initialize(Action)} was
* called.
*/
protected String getResourceId() {
return this.resourceLoc.get(2);
}
/** /**
* Returns the {@link ExecutionHandler} * Returns the {@link ExecutionHandler}
* *
@ -144,8 +163,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
} }
/** /**
* Performs any initialization of this {@link ExecutionPolicy} for the given action, this method stores the {@link * Performs any initialization of this {@link ExecutionPolicy} for the given action, this method stores the
* Locator} of the action and its type * {@link Locator} of the action and its type
* *
* @param action * @param action
* the action for which to initialize * the action for which to initialize
@ -153,6 +172,7 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
public void initialize(Action action) { public void initialize(Action action) {
this.actionType = action.getType(); this.actionType = action.getType();
this.actionLoc = action.getLocator(); this.actionLoc = action.getLocator();
this.resourceLoc = action.getResourceLocator();
} }
/** /**
@ -172,8 +192,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
public abstract void toExecuted(Action action); public abstract void toExecuted(Action action);
/** /**
* Stops the execution of this {@link Action} without completing its execution, i.e. sets the state to {@link * Stops the execution of this {@link Action} without completing its execution, i.e. sets the state to
* State#STOPPED} * {@link State#STOPPED}
* *
* @param action * @param action
* the action to stop execution for * the action to stop execution for
@ -181,8 +201,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
public abstract void toStopped(Action action); public abstract void toStopped(Action action);
/** /**
* Sets this {@link Action} which should be in execution to an error state, i.e. sets the state to {@link * Sets this {@link Action} which should be in execution to an error state, i.e. sets the state to
* State#ERROR} * {@link State#ERROR}
* *
* @param action * @param action
* the action to set to error state * the action to set to error state
@ -190,8 +210,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
public abstract void toError(Action action); public abstract void toError(Action action);
/** /**
* Sets this {@link Action} which should be in execution to a warning state, i.e. sets the state to {@link * Sets this {@link Action} which should be in execution to a warning state, i.e. sets the state to
* State#WARNING} * {@link State#WARNING}
* *
* @param action * @param action
* the action to set to warning state * the action to set to warning state
@ -219,7 +239,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
} }
/** /**
* Updates the state of the given {@link Action} to the given {@link State} and updates the {@link Activity} for persisting on the TX * Updates the state of the given {@link Action} to the given {@link State} and updates the {@link Activity} for
* persisting on the TX
* *
* @param action * @param action
* the action to change * the action to change
@ -241,6 +262,16 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
logger.info(msg); logger.info(msg);
} }
/**
* Finds the duration of the given {@link Action} by searching the activity hierarchy using
* {@link Action#findParameter(String, String, boolean)} using #BAG_OBJECTIVES and #PARAM_DURATION.
*
* @return the {@link DurationParameter}
*/
protected DurationParameter findActionDuration(Action action) {
return action.findParameter(BAG_OBJECTIVES, PARAM_DURATION, true);
}
/** /**
* Delays the given {@link Runnable} by the given {@link Duration} * Delays the given {@link Runnable} by the given {@link Duration}
* *
@ -255,15 +286,16 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
} }
/** /**
* Async method to delay setting the given {@link Action} to executed by the duration defined by the {@link DurationParameter} found by calling {@link Action#findParameter(String, String, boolean)} * Async method to delay setting the given {@link Action} to executed by the duration defined by the
* {@link DurationParameter} found by calling {@link Action#findParameter(String, String, boolean)}
*/ */
protected void delayToExecuted(Action action) { protected void delayToExecuted(Action action) {
DurationParameter durationP = action.findParameter(BAG_OBJECTIVES, PARAM_DURATION, true); delayToExecutedBy(findActionDuration(action));
delayToExecutedBy(durationP);
} }
/** /**
* Async method to delay setting the {@link Action} to executed by the duration defined by the given {@link DurationParameter} * Async method to delay setting the {@link Action} to executed by the duration defined by the given
* {@link DurationParameter}
*/ */
protected void delayToExecutedBy(DurationParameter durationP) { protected void delayToExecutedBy(DurationParameter durationP) {
long duration = durationP.getValue().toMillis(); long duration = durationP.getValue().toMillis();
@ -278,8 +310,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
} }
/** /**
* Async method to delay setting the {@link Action} to executed by the given duration, * Async method to delay setting the {@link Action} to executed by the given duration, but randomly changing the
* but randomly changing the duration in milliseconds by the given min and max factors * duration in milliseconds by the given min and max factors
*/ */
protected void delayToExecutedByRandom(Duration duration, double minFactor, double maxFactor) { protected void delayToExecutedByRandom(Duration duration, double minFactor, double maxFactor) {
long durationMs = duration.toMillis(); long durationMs = duration.toMillis();
@ -287,19 +319,17 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
} }
/** /**
* Async method to delay setting the given {@link Action} to executed by the duration defined * Async method to delay setting the given {@link Action} to executed by the duration defined by the
* by the {@link DurationParameter} found by calling {@link Action#findParameter(String, String, boolean)}, * {@link DurationParameter} found by calling {@link Action#findParameter(String, String, boolean)}, but randomly
* but randomly changing the duration in milliseconds by the given min and max factors * changing the duration in milliseconds by the given min and max factors
*/ */
protected void delayToExecutedByRandom(Action action, double minFactor, double maxFactor) { protected void delayToExecutedByRandom(Action action, double minFactor, double maxFactor) {
DurationParameter durationP = action.findParameter(BAG_OBJECTIVES, PARAM_DURATION, true); delayToExecutedByRandom(findActionDuration(action), minFactor, maxFactor);
delayToExecutedByRandom(durationP, minFactor, maxFactor);
} }
/** /**
* Async method to delay setting the {@link Action} to executed * Async method to delay setting the {@link Action} to executed by the duration defined by the given
* by the duration defined by the given {@link DurationParameter}, * {@link DurationParameter}, but randomly changing the duration in milliseconds by the given min and max factors
* but randomly changing the duration in milliseconds by the given min and max factors
*/ */
protected void delayToExecutedByRandom(DurationParameter durationP, double minFactor, double maxFactor) { protected void delayToExecutedByRandom(DurationParameter durationP, double minFactor, double maxFactor) {
long duration = durationP.getValue().toMillis(); long duration = durationP.getValue().toMillis();
@ -307,16 +337,16 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
} }
/** /**
* Async method to delay setting the {@link Action} to executed by the given duration, * Async method to delay setting the {@link Action} to executed by the given duration, but randomly changing the
* but randomly changing the duration in milliseconds by the given min and max factors * duration in milliseconds by the given min and max factors
*/ */
protected void delayToExecutedByRandom(long duration, double minFactor, double maxFactor, TimeUnit delayUnit) { protected void delayToExecutedByRandom(long duration, double minFactor, double maxFactor, TimeUnit delayUnit) {
delayToExecutedByRandom((long) (duration * minFactor), (long) (duration * maxFactor), delayUnit); delayToExecutedByRandom((long) (duration * minFactor), (long) (duration * maxFactor), delayUnit);
} }
/** /**
* Async method to delay setting the {@link Action} to executed by randomly choosing a value * Async method to delay setting the {@link Action} to executed by randomly choosing a value by calling
* by calling {@link ThreadLocalRandom#nextLong(long, long)} passing min and max as origin and bound respectively * {@link ThreadLocalRandom#nextLong(long, long)} passing min and max as origin and bound respectively
*/ */
protected void delayToExecutedByRandom(long min, long max, TimeUnit delayUnit) { protected void delayToExecutedByRandom(long min, long max, TimeUnit delayUnit) {
long delay = ThreadLocalRandom.current().nextLong(min, max + 1); long delay = ThreadLocalRandom.current().nextLong(min, max + 1);
@ -345,13 +375,14 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
* @return the {@link DelayedExecutionTimer} to simplify the delayed execution of an {@link Action}, e.g. for * @return the {@link DelayedExecutionTimer} to simplify the delayed execution of an {@link Action}, e.g. for
* simulated execution or simple wait tasks * simulated execution or simple wait tasks
*/ */
private DelayedExecutionTimer getDelayedExecutionTimer() { protected DelayedExecutionTimer getDelayedExecutionTimer() {
return getComponent(ExecutionHandler.class).getDelayedExecutionTimer(); return getComponent(ExecutionHandler.class).getDelayedExecutionTimer();
} }
/** /**
* Opens a {@link StrolchTransaction} where the realm retrieved using {@link ComponentContainer#getRealm(Certificate)}. * Opens a {@link StrolchTransaction} where the realm retrieved using
* This transaction should be used in a try-with-resource clause so it is properly closed. * {@link ComponentContainer#getRealm(Certificate)}. This transaction should be used in a try-with-resource clause
* so it is properly closed.
* *
* @param ctx * @param ctx
* the privilege context * the privilege context
@ -387,8 +418,8 @@ public abstract class ExecutionPolicy extends StrolchPolicy {
} }
/** /**
* Performs the given {@link PrivilegedRunnableWithResult} as the system user {@link * Performs the given {@link PrivilegedRunnableWithResult} as the system user
* StrolchConstants#SYSTEM_USER_AGENT} * {@link StrolchConstants#SYSTEM_USER_AGENT}
* *
* @param runnable * @param runnable
* the runnable to perform * the runnable to perform

View File

@ -1,7 +1,9 @@
package li.strolch.execution.policy; package li.strolch.execution.policy;
import java.util.concurrent.ScheduledFuture;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
import li.strolch.exception.StrolchException; import li.strolch.exception.StrolchException;
import li.strolch.execution.ExecutionHandler; import li.strolch.execution.ExecutionHandler;
@ -9,10 +11,12 @@ import li.strolch.handler.operationslog.OperationsLog;
import li.strolch.model.State; import li.strolch.model.State;
import li.strolch.model.activity.Action; import li.strolch.model.activity.Action;
import li.strolch.model.log.LogMessage; import li.strolch.model.log.LogMessage;
import li.strolch.model.parameter.DurationParameter;
import li.strolch.model.timevalue.impl.FloatValue; import li.strolch.model.timevalue.impl.FloatValue;
import li.strolch.model.timevalue.impl.ValueChange; import li.strolch.model.timevalue.impl.ValueChange;
import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.PrivilegeContext; import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.utils.time.PeriodDuration;
/** /**
* <p> * <p>
@ -23,10 +27,36 @@ import li.strolch.privilege.model.PrivilegeContext;
*/ */
public class SimpleExecution extends ExecutionPolicy { public class SimpleExecution extends ExecutionPolicy {
private ScheduledFuture<?> warningTask;
public SimpleExecution(StrolchTransaction tx) { public SimpleExecution(StrolchTransaction tx) {
super(tx); super(tx);
} }
protected void startWarningTask(Action action, Supplier<LogMessage> handler) {
DurationParameter durationP = findActionDuration(action);
startWarningTask(durationP.getValue(), action, handler);
}
protected void startWarningTask(PeriodDuration duration, Action action, Supplier<LogMessage> handler) {
if (this.warningTask != null) {
logger.warn("There is already a warning task registered, for action " + action.getLocator()
+ ". Cancelling and creating a new task...");
this.warningTask.cancel(true);
this.warningTask = null;
}
DurationParameter durationP = findActionDuration(action);
this.warningTask = getDelayedExecutionTimer().delay(durationP.getValue(), () -> toWarning(handler.get()));
}
protected void cancelWarningTask() {
if (this.warningTask != null) {
this.warningTask.cancel(true);
this.warningTask = null;
}
}
@Override @Override
public void toExecution(Action action) { public void toExecution(Action action) {
setActionState(action, State.EXECUTION); setActionState(action, State.EXECUTION);
@ -42,6 +72,7 @@ public class SimpleExecution extends ExecutionPolicy {
@Override @Override
public void toExecuted(Action action) { public void toExecuted(Action action) {
cancelWarningTask();
stop(); stop();
setActionState(action, State.EXECUTED); setActionState(action, State.EXECUTED);
@ -52,6 +83,7 @@ public class SimpleExecution extends ExecutionPolicy {
@Override @Override
public void toStopped(Action action) { public void toStopped(Action action) {
cancelWarningTask();
stop(); stop();
setActionState(action, State.STOPPED); setActionState(action, State.STOPPED);
@ -62,6 +94,7 @@ public class SimpleExecution extends ExecutionPolicy {
@Override @Override
public void toError(Action action) { public void toError(Action action) {
cancelWarningTask();
stop(); stop();
setActionState(action, State.ERROR); setActionState(action, State.ERROR);
@ -78,12 +111,14 @@ public class SimpleExecution extends ExecutionPolicy {
} }
protected void toExecuted() throws Exception { protected void toExecuted() throws Exception {
cancelWarningTask();
stop(); stop();
getController().toExecuted(this.actionLoc); getController().toExecuted(this.actionLoc);
getComponent(ExecutionHandler.class).triggerExecution(this.realm); getComponent(ExecutionHandler.class).triggerExecution(this.realm);
} }
protected void toError(LogMessage message) { protected void toError(LogMessage message) {
cancelWarningTask();
stop(); stop();
logger.error("Action " + message.getLocator() + " failed because of: " + message.formatMessage()); logger.error("Action " + message.getLocator() + " failed because of: " + message.formatMessage());
addMessage(message); addMessage(message);
@ -91,6 +126,7 @@ public class SimpleExecution extends ExecutionPolicy {
} }
protected void toWarning(LogMessage message) { protected void toWarning(LogMessage message) {
cancelWarningTask();
stop(); stop();
addMessage(message); addMessage(message);
getController().asyncToWarning(message.getLocator()); getController().asyncToWarning(message.getLocator());