Added proper abort scenario for shell scripts (kill of process)
Added code to ensure that data stream is terminated (and therefor written) regardless whether something was failing during a scan.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>fda</artifactId>
|
||||
<version>1.1.30</version>
|
||||
<version>1.1.31</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -35,6 +35,9 @@ public class ShellAction implements Action{
|
||||
// Get Logger
|
||||
private static Logger logger = Logger.getLogger(ShellAction.class.getName());
|
||||
|
||||
private volatile Process process;
|
||||
private volatile boolean abort = false;
|
||||
|
||||
/**
|
||||
* Name (full path if it is not in the system path) of the script to execute when
|
||||
* the execute() function of this action is invoked.
|
||||
@@ -67,15 +70,22 @@ public class ShellAction implements Action{
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
try{
|
||||
abort = false;
|
||||
logger.fine("Execute script "+script);
|
||||
Process process = Runtime.getRuntime().exec(script);
|
||||
process = Runtime.getRuntime().exec(script);
|
||||
int exitValue = process.waitFor();
|
||||
logger.fine("Script ["+script+"] return value: "+exitValue);
|
||||
|
||||
// Check script exit value to 0 if != 0 then throw an runtime exception
|
||||
if(exitValue != 0){
|
||||
throw new RuntimeException("Script ["+script+"] returned with an exit value not equal to 0");
|
||||
if(abort){
|
||||
throw new RuntimeException("Script ["+script+"] was aborted");
|
||||
}
|
||||
else{
|
||||
// Check script exit value to 0 if != 0 then throw an runtime exception
|
||||
if(exitValue != 0){
|
||||
throw new RuntimeException("Script ["+script+"] returned with an exit value not equal to 0");
|
||||
}
|
||||
}
|
||||
process = null; // Ensure that the process is null
|
||||
}
|
||||
catch(IOException e){
|
||||
// Convert Exception into unchecked RuntimeException
|
||||
@@ -88,7 +98,12 @@ public class ShellAction implements Action{
|
||||
*/
|
||||
@Override
|
||||
public void abort() {
|
||||
abort=true;
|
||||
// This action cannot be aborted, therefore this function is not implemented.
|
||||
if(process!=null){
|
||||
// Terminate process via kill
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
@@ -191,151 +191,157 @@ public class ActorSensorLoop implements ActionLoop {
|
||||
// Variable to store the last guard status
|
||||
boolean guardOK=true;
|
||||
|
||||
// Execute loop logic
|
||||
while(loop){
|
||||
try{
|
||||
|
||||
if(guardOK){
|
||||
// Execute loop logic
|
||||
while(loop){
|
||||
|
||||
|
||||
// If actors are defined for the loop check whether all of them
|
||||
// have a next step defined if there is no actor defined only run this loop once
|
||||
if(actors.size()>0){
|
||||
// Check whether the actors of this loop have a next step. If not
|
||||
// abort the loop
|
||||
boolean hasNext = true;
|
||||
for(Actor actor: actors){
|
||||
if(!actor.hasNext()){
|
||||
hasNext=false;
|
||||
break; // Stop actor check loop
|
||||
if(guardOK){
|
||||
|
||||
|
||||
// If actors are defined for the loop check whether all of them
|
||||
// have a next step defined if there is no actor defined only run this loop once
|
||||
if(actors.size()>0){
|
||||
// Check whether the actors of this loop have a next step. If not
|
||||
// abort the loop
|
||||
boolean hasNext = true;
|
||||
for(Actor actor: actors){
|
||||
if(!actor.hasNext()){
|
||||
hasNext=false;
|
||||
break; // Stop actor check loop
|
||||
}
|
||||
}
|
||||
|
||||
// If not all actors have a next step abort the loop
|
||||
if(!hasNext){
|
||||
break; // Stop action loop
|
||||
}
|
||||
}
|
||||
|
||||
// If not all actors have a next step abort the loop
|
||||
if(!hasNext){
|
||||
break; // Stop action loop
|
||||
else{
|
||||
// No actors defined, only run loop once
|
||||
loop = false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
// No actors defined, only run loop once
|
||||
loop = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Execute pre actor actions
|
||||
for(Action action: preActorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Set actors
|
||||
// for(Actor actor: actors){
|
||||
// actor.set();
|
||||
// }
|
||||
// Parallel set of the actors
|
||||
try {
|
||||
for (Future<Object> f : executorService.invokeAll(pactors)) {
|
||||
f.get(); //Blocks until the async set() is finished
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException("Setting the actors failed",e);
|
||||
}
|
||||
|
||||
// Execute post actor actions
|
||||
for(Action action: postActorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(guard!=null){
|
||||
// Initialize guard
|
||||
guard.init();
|
||||
guardOK=guard.check();
|
||||
|
||||
// Wait until guard is ok
|
||||
while(!guardOK){
|
||||
logger.info("Waiting for guard condition(s) to be met");
|
||||
// Sleep 100 milliseconds before next check
|
||||
Thread.sleep(1000);
|
||||
|
||||
|
||||
// Check whether the loop is not aborted, if it is aborted
|
||||
// break the wait loop (afterwards also the loop loop is aborted)
|
||||
if(!loop){
|
||||
|
||||
// Execute pre actor actions
|
||||
for(Action action: preActorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Set actors
|
||||
// for(Actor actor: actors){
|
||||
// actor.set();
|
||||
// }
|
||||
// Parallel set of the actors
|
||||
try {
|
||||
for (Future<Object> f : executorService.invokeAll(pactors)) {
|
||||
f.get(); //Blocks until the async set() is finished
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException("Setting the actors failed",e);
|
||||
}
|
||||
|
||||
// Execute post actor actions
|
||||
for(Action action: postActorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(guard!=null){
|
||||
// Initialize guard
|
||||
guard.init();
|
||||
guardOK=guard.check();
|
||||
|
||||
// Wait until guard is ok
|
||||
while(!guardOK){
|
||||
logger.info("Waiting for guard condition(s) to be met");
|
||||
// Sleep 100 milliseconds before next check
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Check whether the loop is not aborted, if it is aborted
|
||||
// break the wait loop (afterwards also the loop loop is aborted)
|
||||
if(!loop){
|
||||
break;
|
||||
}
|
||||
|
||||
guard.init();
|
||||
guardOK=guard.check();
|
||||
}
|
||||
|
||||
// If loop is aborted proceed to next iteration an abort loop
|
||||
if(!loop){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Execute pre sensor actions
|
||||
for(Action action: preSensorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Read sensors
|
||||
DataMessage message = new DataMessage();
|
||||
for(Sensor sensor: sensors){
|
||||
// Readout sensor
|
||||
Object o = sensor.read();
|
||||
// Add sensor data item to message
|
||||
message.getData().add(o);
|
||||
}
|
||||
|
||||
// Execute post sensor actions
|
||||
for(Action action: postSensorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Check guard if one is registered
|
||||
if(guard!=null){
|
||||
guardOK=guard.check();
|
||||
}
|
||||
|
||||
// If loop is aborted proceed to next iteration an abort loop
|
||||
if(!loop){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Execute pre sensor actions
|
||||
for(Action action: preSensorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Read sensors
|
||||
DataMessage message = new DataMessage();
|
||||
for(Sensor sensor: sensors){
|
||||
// Readout sensor
|
||||
Object o = sensor.read();
|
||||
// Add sensor data item to message
|
||||
message.getData().add(o);
|
||||
}
|
||||
|
||||
// Execute post sensor actions
|
||||
for(Action action: postSensorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Check guard if one is registered
|
||||
if(guard!=null){
|
||||
guardOK=guard.check();
|
||||
}
|
||||
|
||||
if(guardOK){
|
||||
|
||||
// Post a message with the sensor data
|
||||
dataQueue.put(message);
|
||||
if(guardOK){
|
||||
|
||||
// Loop all configured ActionLoop objects
|
||||
for(ActionLoop actionLoop: actionLoops){
|
||||
actionLoop.execute();
|
||||
// Post a message with the sensor data
|
||||
dataQueue.put(message);
|
||||
|
||||
// Loop all configured ActionLoop objects
|
||||
for(ActionLoop actionLoop: actionLoops){
|
||||
actionLoop.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
finally{
|
||||
// Ensure that data stream is terminated ...
|
||||
|
||||
// Issue end of loop control message
|
||||
// Set iflag of the EndOfStreamMessage according to dataGroup flag of this loop
|
||||
dataQueue.put(new EndOfStreamMessage(dataGroup));
|
||||
}
|
||||
|
||||
|
||||
// Issue end of loop control message
|
||||
// Set iflag of the EndOfStreamMessage according to dataGroup flag of this loop
|
||||
dataQueue.put(new EndOfStreamMessage(dataGroup));
|
||||
|
||||
if(zigZag){
|
||||
// Reverse actors for the next run
|
||||
for(Actor actor: actors){
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
handlers = java.util.logging.ConsoleHandler
|
||||
|
||||
# Set the default logging level for the root logger
|
||||
.level=INFO
|
||||
.level=ALL
|
||||
|
||||
# Set the default logging level for new ConsoleHandler instances
|
||||
java.util.logging.ConsoleHandler.level=ALL
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration numberOfExecution="0" xmlns="http://www.psi.ch/~ebner/models/scan/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.psi.ch/~ebner/models/scan/1.0 ../../src/model-v1.xsd">
|
||||
<!--
|
||||
1D Scan reading out scalar channels and the timestamp for each point
|
||||
-->
|
||||
<data format="txt"/>
|
||||
<scan id="">
|
||||
<dimension zigzag="true">
|
||||
<positioner id="id0" name="MTEST-HW3:MOT1" settlingTime="0.1" xsi:type="LinearPositioner">
|
||||
<start>0.0</start>
|
||||
<end>8.0</end>
|
||||
<stepSize>0.5</stepSize>
|
||||
</positioner>
|
||||
<detector id="idD0" xsi:type="ScalarDetector" name="MTEST-HW3:MOT1.RRBV">
|
||||
<preAction xsi:type="ShellAction" command="/Users/ebner/git/jfda/ch.psi.fda/src/test/resources/testscripts/errorscript.sh"/>
|
||||
</detector>
|
||||
<detector id="idD1" xsi:type="ScalarDetector" name="MTEST-HW3:MOT1.RBV"/>
|
||||
<detector xsi:type="Timestamp" id="timestamp"/>
|
||||
</dimension>
|
||||
</scan>
|
||||
|
||||
<visualization title="Line Plot One" xsi:type="LinePlot" x="id0" y="idD0"/>
|
||||
<visualization title="Line Plot Two" xsi:type="LinePlot" x="id0" y="idD1"/>
|
||||
<visualization xsi:type="LinePlot" x="id0" y="timestamp" title="Timestamp" />
|
||||
</configuration>
|
||||
11
ch.psi.fda/src/test/resources/testscripts/errorscript.sh
Executable file
11
ch.psi.fda/src/test/resources/testscripts/errorscript.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
echo "Error Script"
|
||||
if [ -f /tmp/error.tmp ]; then
|
||||
echo "Error Occured"
|
||||
sleep 20
|
||||
exit 1
|
||||
fi
|
||||
sleep 4
|
||||
touch /tmp/error.tmp
|
||||
echo "Return Error Script"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user