@Override public CompletionStage<Backfill> backfillCreate(String componentId, String workflowId, String start, String end, int concurrency, String description) { final BackfillInput backfill = BackfillInput.newBuilder() .start(Instant.parse(start)) .end(Instant.parse(end)) .component(componentId) .workflow(workflowId) .concurrency(concurrency) .description(Optional.ofNullable(description)) .build(); return backfillCreate(backfill); }
final WorkflowId workflowId = WorkflowId.create(input.component(), input.workflow()); final Workflow workflow; try { activeWorkflowInstances = storage.readActiveStates(input.component()).keySet(); } catch (Exception e) { throw new RuntimeException(e); final List<Instant> instants = instantsInRange(input.start(), input.end(), schedule); final List<WorkflowInstance> alreadyActive = instants.stream() .allTriggered(false) .workflowId(workflowId) .concurrency(input.concurrency()) .start(input.start()) .end(input.end()) .schedule(schedule) .nextTrigger(input.reverse() ? Iterables.getLast(instants) : input.start()) .description(input.description()) .reverse(input.reverse()) .triggerParameters(input.triggerParameters()) .halted(false);
private Optional<String> validate(RequestContext rc, BackfillInput input, Workflow workflow) { if (!workflow.configuration().dockerImage().isPresent()) { return Optional.of("Workflow is missing docker image"); } final Collection<String> errors = workflowValidator.validateWorkflow(workflow); if (!errors.isEmpty()) { return Optional.of("Invalid workflow configuration: " + String.join(", ", errors)); } final Schedule schedule = workflow.configuration().schedule(); if (!input.start().isBefore(input.end())) { return Optional.of("start must be before end"); } if (!TimeUtil.isAligned(input.start(), schedule)) { return Optional.of("start parameter not aligned with schedule"); } if (!TimeUtil.isAligned(input.end(), schedule)) { return Optional.of("end parameter not aligned with schedule"); } final boolean allowFuture = Boolean.parseBoolean(rc.request().parameter("allowFuture").orElse("false")); if (!allowFuture && (input.start().isAfter(time.get()) || TimeUtil.previousInstant(input.end(), schedule).isAfter(time.get()))) { return Optional.of("Cannot backfill future partitions"); } return Optional.empty(); }
private void backfillCreate() throws ExecutionException, InterruptedException { final String component = namespace.getString(parser.backfillCreateComponent.getDest()); final String workflow = namespace.getString(parser.backfillCreateWorkflow.getDest()); final String start = namespace.getString(parser.backfillCreateStart.getDest()); final String end = namespace.getString(parser.backfillCreateEnd.getDest()); final boolean reverse = namespace.getBoolean(parser.backfillCreateReverse.getDest()); final int concurrency = namespace.getInt(parser.backfillCreateConcurrency.getDest()); final String description = namespace.getString(parser.backfillCreateDescription.getDest()); final TriggerParameters triggerParameters = TriggerParameters.builder() .env(parser.getEnvVars(namespace, parser.backfillCreateEnv)) .build(); final BackfillInput configuration = BackfillInput.newBuilder() .component(component) .workflow(workflow) .start(Instant.parse(start)) .end(Instant.parse(end)) .reverse(reverse) .concurrency(concurrency) .description(description) .triggerParameters(triggerParameters) .build(); final boolean allowFuture = namespace.getBoolean(parser.backfillCreateAllowFuture.getDest()); final Backfill backfill = styxClient.backfillCreate(configuration, allowFuture) .toCompletableFuture().get(); cliOutput.printBackfill(backfill, true); }