Watcher: Add execution state to watch status (elastic/x-pack-elasticsearch#2699)
The execution state is kind of a global indicator if a watch has been running successfully and is used by the watcher UI. However this field is only stored in the watch history but not part of the watch status, thus it is not available everywhere. In order to simplify the watcher UI this commit also adds the field to the watch status which is stored together with the watch. It is stored under the `status.execution_state` field as `status.state` is already taken. This is also reflects with the name of the java class. The WatchStatus class does not contain serialization checks, as this is intended to be backported to 6.x, where those checks will be added. Once the backport is done, the old execution state field can be fully deleted from the master branch in another commit (syncing with Kibana folks required). relates elastic/x-pack-elasticsearch#2385 * fix doc tests Original commit: elastic/x-pack-elasticsearch@26e8f99571
This commit is contained in:
parent
cadfd03529
commit
80593fb23c
|
@ -148,6 +148,7 @@ and the action is now in `ackable` state:
|
|||
}
|
||||
},
|
||||
"state": ...,
|
||||
"execution_state": "executed",
|
||||
"last_checked": ...,
|
||||
"last_met_condition": ...
|
||||
},
|
||||
|
@ -195,6 +196,7 @@ GET _xpack/watcher/watch/my_watch
|
|||
}
|
||||
},
|
||||
"state": ...,
|
||||
"execution_state": "executed",
|
||||
"last_checked": ...,
|
||||
"last_met_condition": ...
|
||||
},
|
||||
|
@ -260,6 +262,7 @@ The response looks like a get watch response, but only contains the status:
|
|||
}
|
||||
}
|
||||
},
|
||||
"execution_state": "executed",
|
||||
"version": 2
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,6 +185,7 @@ This is an example of the output:
|
|||
"state": "executed",
|
||||
"status": {
|
||||
"version": 1,
|
||||
"execution_state": "executed",
|
||||
"state": {
|
||||
"active": true,
|
||||
"timestamp": "2015-06-02T23:17:55.111Z"
|
||||
|
|
|
@ -202,25 +202,27 @@ public abstract class WatchExecutionContext {
|
|||
return Collections.unmodifiableMap(actionsResults);
|
||||
}
|
||||
|
||||
public WatchRecord abortBeforeExecution(ExecutionState state, String message) {
|
||||
WatchRecord abortBeforeExecution(ExecutionState state, String message) {
|
||||
assert !phase.sealed();
|
||||
phase = ExecutionPhase.ABORTED;
|
||||
return new WatchRecord.MessageWatchRecord(id, triggerEvent, state, message, getNodeId());
|
||||
}
|
||||
|
||||
public WatchRecord abortFailedExecution(String message) {
|
||||
WatchRecord abortFailedExecution(String message) {
|
||||
assert !phase.sealed();
|
||||
phase = ExecutionPhase.ABORTED;
|
||||
long executionTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - relativeStartTime);
|
||||
WatchExecutionResult result = new WatchExecutionResult(this, executionTime);
|
||||
watch().status().setExecutionState(WatchRecord.getState(result));
|
||||
return new WatchRecord.MessageWatchRecord(this, result, message);
|
||||
}
|
||||
|
||||
public WatchRecord abortFailedExecution(Exception e) {
|
||||
WatchRecord abortFailedExecution(Exception e) {
|
||||
assert !phase.sealed();
|
||||
phase = ExecutionPhase.ABORTED;
|
||||
long executionTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - relativeStartTime);
|
||||
WatchExecutionResult result = new WatchExecutionResult(this, executionTime);
|
||||
watch().status().setExecutionState(WatchRecord.getState(result));
|
||||
return new WatchRecord.ExceptionWatchRecord(this, result, e);
|
||||
}
|
||||
|
||||
|
@ -229,10 +231,11 @@ public abstract class WatchExecutionContext {
|
|||
phase = ExecutionPhase.FINISHED;
|
||||
long executionTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - relativeStartTime);
|
||||
WatchExecutionResult result = new WatchExecutionResult(this, executionTime);
|
||||
watch().status().setExecutionState(WatchRecord.getState(result));
|
||||
return new WatchRecord.MessageWatchRecord(this, result);
|
||||
}
|
||||
|
||||
public WatchExecutionSnapshot createSnapshot(Thread executionThread) {
|
||||
WatchExecutionSnapshot createSnapshot(Thread executionThread) {
|
||||
return new WatchExecutionSnapshot(this, executionThread.getStackTrace());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ public abstract class WatchRecord implements ToXContentObject {
|
|||
context.watch().condition(), context.watch().metadata(), context.watch(), executionResult, context.getNodeId());
|
||||
}
|
||||
|
||||
private static ExecutionState getState(WatchExecutionResult executionResult) {
|
||||
public static ExecutionState getState(WatchExecutionResult executionResult) {
|
||||
if (executionResult == null || executionResult.conditionResult() == null) {
|
||||
return ExecutionState.FAILED;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import org.elasticsearch.xpack.watcher.actions.Action;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionStatus;
|
||||
import org.elasticsearch.xpack.watcher.actions.throttler.AckThrottler;
|
||||
import org.elasticsearch.xpack.watcher.execution.ExecutionState;
|
||||
import org.elasticsearch.xpack.watcher.support.xcontent.WatcherXContentParser;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
|
@ -41,6 +42,7 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
|
||||
private State state;
|
||||
|
||||
@Nullable private ExecutionState executionState;
|
||||
@Nullable private DateTime lastChecked;
|
||||
@Nullable private DateTime lastMetCondition;
|
||||
@Nullable private long version;
|
||||
|
@ -51,19 +53,21 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
}
|
||||
|
||||
public WatchStatus(DateTime now, Map<String, ActionStatus> actions) {
|
||||
this(-1, new State(true, now), null, null, actions);
|
||||
this(-1, new State(true, now), null, null, null, actions);
|
||||
}
|
||||
|
||||
public WatchStatus(WatchStatus other) {
|
||||
this(other.version, other.state, other.lastChecked, other.lastMetCondition, other.actions);
|
||||
this(other.version, other.state, other.executionState, other.lastChecked, other.lastMetCondition, other.actions);
|
||||
}
|
||||
|
||||
private WatchStatus(long version, State state, DateTime lastChecked, DateTime lastMetCondition, Map<String, ActionStatus> actions) {
|
||||
private WatchStatus(long version, State state, ExecutionState executionState, DateTime lastChecked, DateTime lastMetCondition,
|
||||
Map<String, ActionStatus> actions) {
|
||||
this.version = version;
|
||||
this.lastChecked = lastChecked;
|
||||
this.lastMetCondition = lastMetCondition;
|
||||
this.actions = actions;
|
||||
this.state = state;
|
||||
this.executionState = executionState;
|
||||
}
|
||||
|
||||
public State state() {
|
||||
|
@ -90,6 +94,14 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
this.version = version;
|
||||
}
|
||||
|
||||
public void setExecutionState(ExecutionState executionState) {
|
||||
this.executionState = executionState;
|
||||
}
|
||||
|
||||
public ExecutionState getExecutionState() {
|
||||
return executionState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -100,12 +112,13 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
return Objects.equals(lastChecked, that.lastChecked) &&
|
||||
Objects.equals(lastMetCondition, that.lastMetCondition) &&
|
||||
Objects.equals(version, that.version) &&
|
||||
Objects.equals(executionState, that.executionState) &&
|
||||
Objects.equals(actions, that.actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(lastChecked, lastMetCondition, actions, version);
|
||||
return Objects.hash(lastChecked, lastMetCondition, actions, version, executionState);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,6 +198,10 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
}
|
||||
out.writeBoolean(state.active);
|
||||
writeDate(out, state.timestamp);
|
||||
out.writeBoolean(executionState != null);
|
||||
if (executionState != null) {
|
||||
out.writeString(executionState.id());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -199,6 +216,10 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
}
|
||||
this.actions = unmodifiableMap(actions);
|
||||
state = new State(in.readBoolean(), readDate(in, UTC));
|
||||
boolean executionStateExists = in.readBoolean();
|
||||
if (executionStateExists) {
|
||||
executionState = ExecutionState.resolve(in.readString());
|
||||
}
|
||||
}
|
||||
|
||||
public static WatchStatus read(StreamInput in) throws IOException {
|
||||
|
@ -226,12 +247,16 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
}
|
||||
builder.endObject();
|
||||
}
|
||||
if (executionState != null) {
|
||||
builder.field(Field.EXECUTION_STATE.getPreferredName(), executionState.id());
|
||||
}
|
||||
builder.field(Field.VERSION.getPreferredName(), version);
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
public static WatchStatus parse(String watchId, XContentParser parser, Clock clock) throws IOException {
|
||||
State state = null;
|
||||
ExecutionState executionState = null;
|
||||
DateTime lastChecked = null;
|
||||
DateTime lastMetCondition = null;
|
||||
Map<String, ActionStatus> actions = null;
|
||||
|
@ -270,6 +295,13 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
throw new ElasticsearchParseException("could not parse watch status for [{}]. expecting field [{}] to hold a date " +
|
||||
"value, found [{}] instead", watchId, currentFieldName, token);
|
||||
}
|
||||
} else if (Field.EXECUTION_STATE.match(currentFieldName)) {
|
||||
if (token.isValue()) {
|
||||
executionState = ExecutionState.resolve(parser.text());
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not parse watch status for [{}]. expecting field [{}] to hold a string " +
|
||||
"value, found [{}] instead", watchId, currentFieldName, token);
|
||||
}
|
||||
} else if (Field.ACTIONS.match(currentFieldName)) {
|
||||
actions = new HashMap<>();
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
|
@ -296,7 +328,7 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
}
|
||||
actions = actions == null ? emptyMap() : unmodifiableMap(actions);
|
||||
|
||||
return new WatchStatus(version, state, lastChecked, lastMetCondition, actions);
|
||||
return new WatchStatus(version, state, executionState, lastChecked, lastMetCondition, actions);
|
||||
}
|
||||
|
||||
public static class State implements ToXContentObject {
|
||||
|
@ -354,5 +386,6 @@ public class WatchStatus implements ToXContentObject, Streamable {
|
|||
ParseField LAST_MET_CONDITION = new ParseField("last_met_condition");
|
||||
ParseField ACTIONS = new ParseField("actions");
|
||||
ParseField VERSION = new ParseField("version");
|
||||
ParseField EXECUTION_STATE = new ParseField("execution_state");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -813,6 +813,8 @@ public class ExecutionServiceTests extends ESTestCase {
|
|||
public void testThatTriggeredWatchDeletionWorksOnExecutionRejection() throws Exception {
|
||||
Watch watch = mock(Watch.class);
|
||||
when(watch.id()).thenReturn("foo");
|
||||
WatchStatus status = new WatchStatus(DateTime.now(UTC), Collections.emptyMap());
|
||||
when(watch.status()).thenReturn(status);
|
||||
GetResponse getResponse = mock(GetResponse.class);
|
||||
when(getResponse.isExists()).thenReturn(true);
|
||||
when(getResponse.getId()).thenReturn("foo");
|
||||
|
|
|
@ -58,6 +58,7 @@ teardown:
|
|||
- match: { watch_record.trigger_event.triggered_time: "2012-12-12T12:12:12.120Z" }
|
||||
- match: { watch_record.trigger_event.manual.schedule.scheduled_time: "2000-12-12T12:12:12.120Z" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.status.state.active: true }
|
||||
- is_true: watch_record.node
|
||||
- match: { watch_record.status.actions.indexme.ack.state: "ackable" }
|
||||
|
@ -97,6 +98,7 @@ teardown:
|
|||
- match: { watch_record.watch_id: "_inlined_" }
|
||||
- match: { watch_record.trigger_event.type: "manual" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.status.state.active: true }
|
||||
- match: { watch_record.status.actions.indexme.ack.state: "ackable" }
|
||||
|
||||
|
@ -149,6 +151,7 @@ teardown:
|
|||
|
||||
- match: { watch_record.watch_id: "test_watch" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.status.state.active: true }
|
||||
- is_true: watch_record.node
|
||||
- is_false: watch_record.result.input.payload.foo
|
||||
|
|
|
@ -58,6 +58,7 @@ setup:
|
|||
}
|
||||
- match: { watch_record.trigger_event.type: "manual" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.transform.status: "success" }
|
||||
|
||||
- do:
|
||||
|
@ -131,6 +132,7 @@ setup:
|
|||
}
|
||||
- match: { watch_record.trigger_event.type: "manual" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.transform.status: "success" }
|
||||
|
||||
- do:
|
||||
|
@ -191,6 +193,7 @@ setup:
|
|||
|
||||
- match: { watch_record.trigger_event.type: "manual" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.transform.status: "failure" }
|
||||
- match: { watch_record.result.transform.reason: "no [query] registered for [does_not_exist]" }
|
||||
- is_true: watch_record.result.transform.error
|
||||
|
|
|
@ -56,6 +56,7 @@ teardown:
|
|||
- match: { watch_record.trigger_event.triggered_time: "2012-12-12T12:12:12.120Z" }
|
||||
- match: { watch_record.trigger_event.manual.schedule.scheduled_time: "2000-12-12T12:12:12.120Z" }
|
||||
- match: { watch_record.state: "execution_not_needed" }
|
||||
- match: { watch_record.status.execution_state: "execution_not_needed" }
|
||||
- match: { watch_record.status.state.active: true }
|
||||
|
||||
- do:
|
||||
|
@ -99,6 +100,7 @@ teardown:
|
|||
|
||||
- match: { watch_record.watch_id: "test_watch" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
|
||||
- do:
|
||||
xpack.watcher.execute_watch:
|
||||
|
@ -114,5 +116,6 @@ teardown:
|
|||
|
||||
- match: { watch_record.watch_id: "test_watch" }
|
||||
- match: { watch_record.state: "throttled" }
|
||||
- match: { watch_record.status.execution_state: "throttled" }
|
||||
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ teardown:
|
|||
- match: { watch_record.input.simple.foo: "bar" }
|
||||
- match: { watch_record.trigger_event.type: "manual" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.status.state.active: true }
|
||||
- match: { watch_record.status.actions.logging.ack.state: "ackable" }
|
||||
- is_true: watch_record.condition.never
|
||||
|
|
|
@ -50,6 +50,7 @@ teardown:
|
|||
- match: { watch_record.watch_id: "test_watch" }
|
||||
- match: { watch_record.trigger_event.type: "manual" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.actions.0.id: "logging" }
|
||||
- match: { watch_record.result.actions.0.status: "simulated" }
|
||||
|
||||
|
@ -66,6 +67,7 @@ teardown:
|
|||
- match: { watch_record.watch_id: "test_watch" }
|
||||
- match: { watch_record.trigger_event.type: "manual" }
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.actions.0.id: "logging" }
|
||||
- match: { watch_record.result.actions.0.status: "simulated" }
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ teardown:
|
|||
xpack.watcher.execute_watch:
|
||||
id: "my_watch"
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.actions.0.index.response.id: "test_id1" }
|
||||
|
||||
---
|
||||
|
@ -105,6 +106,7 @@ teardown:
|
|||
xpack.watcher.execute_watch:
|
||||
id: "my_watch"
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.actions.0.index.response.id: "test_id2" }
|
||||
|
||||
---
|
||||
|
@ -163,6 +165,7 @@ teardown:
|
|||
xpack.watcher.execute_watch:
|
||||
id: "my_watch"
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.actions.0.index.response.0.id: "test_id3" }
|
||||
- match: { watch_record.result.actions.0.index.response.1.id: "test_id4" }
|
||||
|
||||
|
@ -220,4 +223,5 @@ teardown:
|
|||
xpack.watcher.execute_watch:
|
||||
id: "my_watch"
|
||||
- match: { watch_record.state: "executed" }
|
||||
- match: { watch_record.status.execution_state: "executed" }
|
||||
- match: { watch_record.result.actions.0.index.response.1.id: "test_id6" }
|
||||
|
|
Loading…
Reference in New Issue