@Override public Optional<Workflow> workflow(WorkflowId workflowId) throws IOException { final Optional<Entity> entityOptional = DatastoreStorage.getOpt(tx, DatastoreStorage.workflowKey(tx.getDatastore().newKeyFactory(), workflowId)); if (entityOptional.isPresent()) { return Optional.of(DatastoreStorage.parseWorkflowJson(entityOptional.get(), workflowId)); } else { return Optional.empty(); } }
@Override public void store(Resource resource) throws IOException { tx.put(resourceToEntity(tx.getDatastore(), resource)); }
@Override public Optional<RunState> readActiveState(WorkflowInstance instance) throws IOException { final Entity entity = tx.get(activeWorkflowInstanceKey(tx.getDatastore().newKeyFactory(), instance)); if (entity == null) { return Optional.empty(); } else { return Optional.of(entityToRunState(entity, instance)); } }
@Override public Optional<Backfill> backfill(String id) throws IOException { final Key key = DatastoreStorage.backfillKey(tx.getDatastore().newKeyFactory(), id); final Entity entity = tx.get(key); if (entity == null) { return Optional.empty(); } return Optional.of(entityToBackfill(entity)); } }
@Override public WorkflowInstance updateActiveState(WorkflowInstance instance, RunState state) throws IOException { tx.update(runStateToEntity(tx.getDatastore().newKeyFactory(), instance, state)); return instance; }
@Override public WorkflowInstance deleteActiveState(WorkflowInstance instance) throws IOException { tx.delete(activeWorkflowInstanceIndexShardEntryKey(tx.getDatastore().newKeyFactory(), instance)); tx.delete(activeWorkflowInstanceKey(tx.getDatastore().newKeyFactory(), instance)); return instance; }
@Override public WorkflowInstance writeActiveState(WorkflowInstance instance, RunState state) throws IOException { // Note: the parent entity need not actually exist final Key indexEntryKey = activeWorkflowInstanceIndexShardEntryKey(tx.getDatastore().newKeyFactory(), instance); final Entity indexEntry = Entity.newBuilder(indexEntryKey).build(); tx.add(indexEntry); tx.add(runStateToEntity(tx.getDatastore().newKeyFactory(), instance, state)); return instance; }
@Override public Optional<Shard> shard(String counterId, int shardIndex) throws IOException { // TODO there's no need for this to be transactional final Key shardKey = tx.getDatastore().newKeyFactory().setKind(KIND_COUNTER_SHARD) .newKey(counterId + "-" + shardIndex); Entity shardEntity = tx.get(shardKey); if (shardEntity == null) { return Optional.empty(); } return Optional.of(Shard.create(counterId, shardIndex, (int) tx.get(shardKey).getLong(PROPERTY_SHARD_VALUE))); }
@Override public WorkflowId patchState(WorkflowId workflowId, WorkflowState state) throws IOException { final Key workflowKey = DatastoreStorage .workflowKey(tx.getDatastore().newKeyFactory(), workflowId); final Optional<Entity> workflowOpt = DatastoreStorage.getOpt(tx, workflowKey); if (!workflowOpt.isPresent()) { throw new ResourceNotFoundException( String.format("%s:%s doesn't exist.", workflowId.componentId(), workflowId.id())); } final Entity.Builder builder = Entity.newBuilder(workflowOpt.get()); state.enabled().ifPresent(x -> builder.set(PROPERTY_WORKFLOW_ENABLED, x)); state.nextNaturalTrigger() .ifPresent(x -> builder.set(PROPERTY_NEXT_NATURAL_TRIGGER, instantToTimestamp(x))); state.nextNaturalOffsetTrigger() .ifPresent(x -> builder.set(PROPERTY_NEXT_NATURAL_OFFSET_TRIGGER, instantToTimestamp(x))); tx.put(builder.build()); return workflowId; }
@Override public void updateLimitForCounter(String counterId, long limit) throws IOException { final Key limitKey = tx.getDatastore().newKeyFactory().setKind(KIND_COUNTER_LIMIT).newKey(counterId); tx.put(Entity.newBuilder(limitKey).set(PROPERTY_LIMIT, limit).build()); }
@Override public WorkflowId updateNextNaturalTrigger(WorkflowId workflowId, TriggerInstantSpec triggerSpec) throws IOException { final Key workflowKey = DatastoreStorage .workflowKey(tx.getDatastore().newKeyFactory(), workflowId); final Optional<Entity> workflowOpt = DatastoreStorage.getOpt(tx, workflowKey); if (!workflowOpt.isPresent()) { throw new ResourceNotFoundException( String.format("%s:%s doesn't exist.", workflowId.componentId(), workflowId.id())); } final Entity.Builder builder = Entity .newBuilder(workflowOpt.get()) .set(PROPERTY_NEXT_NATURAL_TRIGGER, instantToTimestamp(triggerSpec.instant())) .set(PROPERTY_NEXT_NATURAL_OFFSET_TRIGGER, instantToTimestamp(triggerSpec.offsetInstant())); tx.put(builder.build()); return workflowId; }
@Override public WorkflowId store(Workflow workflow) throws IOException { final Key componentKey = DatastoreStorage.componentKey(tx.getDatastore().newKeyFactory(), workflow.componentId()); if (tx.get(componentKey) == null) { tx.put(Entity.newBuilder(componentKey).build()); } final String json = OBJECT_MAPPER.writeValueAsString(workflow); final Key workflowKey = DatastoreStorage.workflowKey(tx.getDatastore().newKeyFactory(), workflow.id()); final Optional<Entity> workflowOpt = DatastoreStorage.getOpt(tx, workflowKey); final Entity workflowEntity = DatastoreStorage.asBuilderOrNew(workflowOpt, workflowKey) .set(PROPERTY_WORKFLOW_JSON, StringValue.newBuilder(json).setExcludeFromIndexes(true).build()) .build(); tx.put(workflowEntity); return workflow.id(); }
@Override public WorkflowId storeWorkflowWithNextNaturalTrigger(Workflow workflow, TriggerInstantSpec triggerSpec) throws IOException { final Key componentKey = DatastoreStorage.componentKey(tx.getDatastore().newKeyFactory(), workflow.componentId()); if (tx.get(componentKey) == null) { tx.put(Entity.newBuilder(componentKey).build()); } final String json = OBJECT_MAPPER.writeValueAsString(workflow); final Key workflowKey = DatastoreStorage.workflowKey(tx.getDatastore().newKeyFactory(), workflow.id()); final Optional<Entity> workflowOpt = DatastoreStorage.getOpt(tx, workflowKey); final Builder entity = DatastoreStorage.asBuilderOrNew(workflowOpt, workflowKey) .set(PROPERTY_WORKFLOW_JSON, StringValue.newBuilder(json).setExcludeFromIndexes(true).build()) .set(PROPERTY_NEXT_NATURAL_TRIGGER, instantToTimestamp(triggerSpec.instant())) .set(PROPERTY_NEXT_NATURAL_OFFSET_TRIGGER, instantToTimestamp(triggerSpec.offsetInstant())); tx.put(entity.build()); return workflow.id(); }
@Override public void store(Shard shard) throws IOException { tx.put(Entity.newBuilder(tx.getDatastore().newKeyFactory().setKind(KIND_COUNTER_SHARD) .newKey(shard.counterId() + "-" + shard.index())) .set(PROPERTY_COUNTER_ID, shard.counterId()) .set(PROPERTY_SHARD_INDEX, shard.index()) .set(PROPERTY_SHARD_VALUE, shard.value()) .build()); }
@Override public Backfill store(Backfill backfill) throws IOException { final Key key = DatastoreStorage.backfillKey(tx.getDatastore().newKeyFactory(), backfill.id()); Entity.Builder builder = Entity.newBuilder(key) .set(PROPERTY_CONCURRENCY, backfill.concurrency()) .set(PROPERTY_START, instantToTimestamp(backfill.start())) .set(PROPERTY_END, instantToTimestamp(backfill.end())) .set(PROPERTY_COMPONENT, backfill.workflowId().componentId()) .set(PROPERTY_WORKFLOW, backfill.workflowId().id()) .set(PROPERTY_SCHEDULE, backfill.schedule().toString()) .set(PROPERTY_NEXT_TRIGGER, instantToTimestamp(backfill.nextTrigger())) .set(PROPERTY_ALL_TRIGGERED, backfill.allTriggered()) .set(PROPERTY_HALTED, backfill.halted()) .set(PROPERTY_REVERSE, backfill.reverse()); backfill.description().ifPresent(x -> builder.set(PROPERTY_DESCRIPTION, StringValue .newBuilder(x).setExcludeFromIndexes(true).build())); if (backfill.triggerParameters().isPresent()) { final String json = OBJECT_MAPPER.writeValueAsString(backfill.triggerParameters().get()); builder.set(PROPERTY_TRIGGER_PARAMETERS, StringValue.newBuilder(json).setExcludeFromIndexes(true).build()); } tx.put(builder.build()); return backfill; }