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:
Alexander Reelsen 2017-10-10 09:07:33 +02:00 committed by GitHub
parent cadfd03529
commit 80593fb23c
12 changed files with 68 additions and 10 deletions

View File

@ -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
}
}

View File

@ -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"

View File

@ -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());
}
}

View File

@ -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;
}

View File

@ -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");
}
}

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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" }

View File

@ -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

View File

@ -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" }

View File

@ -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" }