@Override
  public boolean updateHeartbeat(Execution e, Instant newHeartbeat) {

    final int updated =
        jdbcRunner.execute(
            "update "
                + tableName
                + " set last_heartbeat = ? "
                + "where task_name = ? "
                + "and task_instance = ? "
                + "and version = ?",
            ps -> {
              jdbcCustomization.setInstant(ps, 1, newHeartbeat);
              ps.setString(2, e.taskInstance.getTaskName());
              ps.setString(3, e.taskInstance.getId());
              ps.setLong(4, e.version);
            });

    if (updated == 0) {
      // There is a race-condition: Executions are not removed from currently-executing until after
      // the execution has been updated in the database, so this might happen.
      LOG.debug(
          "Did not update heartbeat. Execution must have been removed or rescheduled"
              + "(i.e. CompletionHandler ran and finished just before heartbeat-update). "
              + "This is a race-condition that may occur, but is very unlikely. "
              + "task-instance={}",
          e.taskInstance);
      return false;
    } else {
      if (updated > 1) {
        LOG.error(
            "Updated multiple rows updating heartbeat for execution. Should never happen since name and id is primary key. Execution: {}",
            e);
        return true;
      }
      LOG.debug("Updated heartbeat for execution: {}", e);
      return true;
    }
  }
Instead of doing delete+insert, we allow updating an existing execution will all new fields

@return the execution-time of the new execution
db-scheduler/src/main/java/com/github/kagkarlsson/scheduler/jdbc/JdbcTaskRepository.java