public Optional<Details> sync(
      @NotNull StepInstance instance,
      @NotNull WorkflowSummary workflowSummary,
      @NotNull StepRuntimeSummary stepSummary) {
    try {
      switch (stepSummary.getDbOperation()) {
        case INSERT:
        case UPSERT:
          instanceDao.insertOrUpsertStepInstance(
              instance, stepSummary.getDbOperation() == DbOperation.UPSERT);
          break;
        case UPDATE:
          instanceDao.updateStepInstance(workflowSummary, stepSummary);
          break;
        default:
          throw new MaestroInternalError(
              "Invalid DB operation: %s for step instance [%s][%s]",
              stepSummary.getDbOperation(),
              stepSummary.getStepId(),
              stepSummary.getStepAttemptId());
      }
      if (!stepSummary.getPendingRecords().isEmpty()) {
        return jobEventPublisher.publish(
            StepInstanceUpdateJobEvent.create(instance, stepSummary.getPendingRecords()));
      }
      return Optional.empty();
    } catch (RuntimeException e) {
      return Optional.of(Details.create(e, true, "Failed to sync a Maestro step state change"));
    }
  }
@Test
  public void testPublishFailure() {
    when(publisher.publish(any())).thenReturn(Optional.of(Details.create("test error")));
    StepRuntimeSummary stepRuntimeSummary =
        StepRuntimeSummary.builder()
            .stepId("test-summary")
            .stepAttemptId(2)
            .stepInstanceId(1)
            .dbOperation(DbOperation.UPDATE)
            .pendingRecords(
                Collections.singletonList(
                    mock(StepInstanceUpdateJobEvent.StepInstancePendingRecord.class)))
            .build();
    Optional<Details> details = syncManager.sync(instance, workflowSummary, stepRuntimeSummary);
    assertTrue(details.isPresent());
    assertEquals("test error", details.get().getMessage());
  }