private RunState state(State state) { return new AutoValue_RunState( workflowInstance(), state, timestamp(), data(), counter()); }
public static RunState create( WorkflowInstance workflowInstance, State state, Instant timestamp, long counter) { return create(workflowInstance, state, StateData.zero(), timestamp, counter); }
private IllegalStateException illegalTransition(String event) { return new IllegalStateException(workflowInstance() + " received " + event + " while in " + state()); }
private RunState transitionUpdates(Instant instant) { return new AutoValue_RunState( workflowInstance(), state(), instant.toEpochMilli(), data(), counter() + 1); }
private void updateResourceCounters(StorageTransaction tx, Event event, RunState currentRunState, RunState nextRunState) throws IOException { // increment counters if event is dequeue if (isDequeue(event) && nextRunState.data().resourceIds().isPresent()) { tryUpdatingCounter(currentRunState, tx, nextRunState.data().resourceIds().get()); } // decrement counters if transitioning from a state that consumes resources // to a state that doesn't consume any resources if (isConsumingResources(currentRunState.state()) && !isConsumingResources(nextRunState.state())) { if (nextRunState.data().resourceIds().isPresent()) { for (String resource : nextRunState.data().resourceIds().get()) { tx.updateCounter(shardedCounter, resource, -1); } } else { log.error("Resource ids are missing for {} when transitioning from {} to {}.", nextRunState.workflowInstance(), currentRunState, nextRunState); } } }
private RunStateData runStateToRunStateData(RunState state) { return RunStateData.newBuilder() .workflowInstance(state.workflowInstance()) .state(state.state().name()) .stateData(state.data()) .latestTimestamp(state.timestamp()) .build(); }
RunState restoredState = RunState.fresh(workflowInstance, time); restoredState = RunState.fresh(workflowInstance, time); initialTime.set(time.get()); restoredState = restoredState.transition(sequenceEvent.event(), time); } catch (IllegalStateException e) { LOG.warn("failed to transition state, move on to next event", e); .workflowInstance(restoredState.workflowInstance()) .state(restoredState.state().name()) .stateData(restoredState.data()) .initialTimestamp(initialTime.get().toEpochMilli()) .latestTimestamp(latestTime.get().toEpochMilli())
.set(PROPERTY_WORKFLOW, wfi.workflowId().id()) .set(PROPERTY_PARAMETER, wfi.parameter()) .set(PROPERTY_COUNTER, state.counter()); .set(PROPERTY_STATE, state.state().toString()) .set(PROPERTY_STATE_TIMESTAMP, state.timestamp()) .set(PROPERTY_STATE_TRIES, state.data().tries()) .set(PROPERTY_STATE_CONSECUTIVE_FAILURES, state.data().consecutiveFailures()) .set(PROPERTY_STATE_RETRY_COST, state.data().retryCost()) .set(PROPERTY_STATE_MESSAGES, jsonValue(state.data().messages())); state.data().retryDelayMillis().ifPresent(v -> entity.set(PROPERTY_STATE_RETRY_DELAY_MILLIS, v)); state.data().lastExit().ifPresent(v -> entity.set(PROPERTY_STATE_LAST_EXIT, v)); state.data().trigger().ifPresent(trigger -> { entity.set(PROPERTY_STATE_TRIGGER_TYPE, TriggerUtil.triggerType(trigger)); entity.set(PROPERTY_STATE_TRIGGER_ID, TriggerUtil.triggerId(trigger)); }); state.data().executionId().ifPresent(v -> entity.set(PROPERTY_STATE_EXECUTION_ID, v)); if (state.data().triggerParameters().isPresent()) { entity.set(PROPERTY_STATE_TRIGGER_PARAMETERS, jsonValue(state.data().triggerParameters().get())); if (state.data().executionDescription().isPresent()) { entity.set(PROPERTY_STATE_EXECUTION_DESCRIPTION, jsonValue(state.data().executionDescription().get())); if (state.data().resourceIds().isPresent()) { entity.set(PROPERTY_STATE_RESOURCE_IDS, jsonValue(state.data().resourceIds().get()));
public static void emitResourceLimitReachedMessage(StateManager stateManager, RunState runState, List<String> depletedResources) { if (depletedResources.isEmpty()) { throw new IllegalArgumentException(); } final List<String> depletedResourcesOrdered = depletedResources.stream().sorted().collect(toList()); final Message message = Message.info("Resource limit reached for: " + depletedResourcesOrdered); if (!runState.data().message().map(message::equals).orElse(false)) { stateManager.receiveIgnoreClosed(Event.info(runState.workflowInstance(), message), runState.counter()); } } }
private boolean shouldExecute(RunState runState) { if (runState.state() != State.QUEUED) { return false; } final Instant now = time.get(); final Instant deadline = Instant .ofEpochMilli(runState.timestamp()) .plusMillis(runState.data().retryDelayMillis().orElse(0L)); return !deadline.isAfter(now); }
nextRunState = currentRunState.get().transition(event, time); } catch (IllegalStateException e) { if (nextRunState.state().isTerminal()) { tx.deleteActiveState(event.workflowInstance()); } else { SequenceEvent.create(event, nextRunState.counter(), nextRunState.timestamp());
private RunState state(State state, StateData newStateData) { return new AutoValue_RunState( workflowInstance(), state, timestamp(), newStateData, counter()); }
private void sendTimeout(WorkflowInstance workflowInstance, RunState runState) { LOG.info("Found stale state {} since {} for workflow {}; Issuing a timeout", runState.state(), Instant.ofEpochMilli(runState.timestamp()), workflowInstance); stateManager.receiveIgnoreClosed(Event.timeout(workflowInstance), runState.counter()); } }
private void examineRunningWFISandAssociatedPods(Map<WorkflowInstance, RunState> activeStates, PodList podList) { final Map<WorkflowInstance, RunState> runningWorkflowInstances = Maps.filterValues(activeStates, runState -> runState.state().equals(RUNNING) && runState.data().executionId().isPresent()); final Set<WorkflowInstance> workflowInstancesForPods = podList.getItems().stream() .map(pod -> pod.getMetadata().getAnnotations()) .filter(Objects::nonNull) .map(annotations -> annotations.get(STYX_WORKFLOW_INSTANCE_ANNOTATION)) .filter(Objects::nonNull) .map(WorkflowInstance::parseKey) .collect(toSet()); // Emit errors for workflow instances that seem to be missing its pod runningWorkflowInstances.forEach((workflowInstance, runState) -> { // Is there a matching pod in the list? Bail. if (workflowInstancesForPods.contains(workflowInstance)) { return; } // The pod list might be stale so explicitly look for a pod using the execution ID. final String executionId = runState.data().executionId().get(); final Pod pod = client.pods().withName(executionId).get(); // We found a pod? Bail. if (pod != null) { return; } // No pod found. Emit an error guarded by the state counter we are basing the error conclusion on. stateManager.receiveIgnoreClosed( Event.runError(workflowInstance, "No pod associated with this instance"), runState.counter()); }); }
private void checkRetry(RunState state) { final WorkflowInstance workflowInstance = state.workflowInstance(); if (state.data().retryCost() < MAX_RETRY_COST) { final Optional<Integer> exitCode = state.data().lastExit(); if (shouldFailFast(exitCode)) { stateManager.receiveIgnoreClosed(Event.stop(workflowInstance)); } else { final long delayMillis; if (isMissingDependency(exitCode)) { delayMillis = Duration.ofMinutes(MISSING_DEPS_RETRY_DELAY_MINUTES).toMillis(); } else { delayMillis = retryUtil.calculateDelay(state.data().consecutiveFailures()).toMillis(); } stateManager.receiveIgnoreClosed(Event.retryAfter(workflowInstance, delayMillis)); } } else { stateManager.receiveIgnoreClosed(Event.stop(workflowInstance)); } }
private static boolean hasTimedOut(Optional<Workflow> workflowOpt, RunState runState, Instant instant, Duration timeout) { if (runState.state().isTerminal()) { return false; } final Duration effectiveTimeout = runState.state() == RunState.State.RUNNING ? workflowOpt .flatMap(workflow -> workflow.configuration().runningTimeout()) .orElse(timeout) : timeout; final Duration sanitizedTimeout = effectiveTimeout.compareTo(timeout) < 0 ? effectiveTimeout : timeout; final Instant deadline = Instant .ofEpochMilli(runState.timestamp()) .plus(sanitizedTimeout); return !deadline.isAfter(instant); }
private void sendDequeue(InstanceState instanceState, Set<String> resourceIds) { final WorkflowInstance workflowInstance = instanceState.workflowInstance(); final RunState state = instanceState.runState(); if (state.data().tries() == 0) { LOG.info("Executing {}", workflowInstance); } else { LOG.info("Executing {}, retry #{}", workflowInstance, state.data().tries()); } stateManager.receiveIgnoreClosed(Event.dequeue(workflowInstance, resourceIds), instanceState.runState().counter()); }
@Override public Map<WorkflowInstance, RunState> readActiveStatesByTriggerId(String triggerId) throws IOException { return activeStatesMap.entrySet().stream() .filter((entry) -> triggerId.equals(TriggerUtil.triggerId(entry.getValue().data().trigger().get()))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); }