@VisibleForTesting
  int deleteAction(StepInstance stepInstance, Actions.StepInstanceAction action) {
    // as the action is an enum, this should be safe without sql injection risk.
    String sql =
        action == null
            ? DELETE_ACTION_QUERY
            : DELETE_ACTION_QUERY + " AND payload->>'action'='" + action.name() + "'";
    return withMetricLogError(
        () ->
            withRetryableUpdate(
                sql,
                stmt -> {
                  int idx = 0;
                  stmt.setString(++idx, stepInstance.getWorkflowId());
                  stmt.setLong(++idx, stepInstance.getWorkflowInstanceId());
                  stmt.setLong(++idx, stepInstance.getWorkflowRunId());
                  stmt.setString(++idx, stepInstance.getStepId());
                }),
        "deleteAction",
        "Failed to delete the action for step {}",
        stepInstance.getIdentity());
  }
@Test
  public void testDelete() {
    testRestartDirectly();
    // delete any action
    Assert.assertEquals(1, actionDao.deleteAction(stepInstance, null));
    testRestartDirectly();
    // delete matched one
    Assert.assertEquals(1, actionDao.deleteAction(stepInstance, RESTART));
    testRestartDirectly();
    // won't delete unmatched one
    Assert.assertEquals(0, actionDao.deleteAction(stepInstance, STOP));
  }