code: private void configure(Member.Type type, CompletableFuture<Void> future) {
      // Set a timer to retry the attempt to leave the cluster.
      configureTimeout = cluster.getContext().getThreadContext().schedule(cluster.getContext().getElectionTimeout(), () -> {
        configure(type, future);
      });
  
      // Attempt to leave the cluster by submitting a LeaveRequest directly to the server state.
      // Non-leader states should forward the request to the leader if there is one. Leader states
      // will log, replicate, and commit the reconfiguration.
      cluster.getContext().getServerState().reconfigure(ReconfigureRequest.builder()
        .withIndex(cluster.getConfiguration().index())
        .withTerm(cluster.getConfiguration().term())
        .withMember(new ServerMember(type, serverAddress(), clientAddress(), updated))
        .build()).whenComplete((response, error) -> {
        if (error == null) {
          if (response.status() == Response.Status.OK) {
            cancelConfigureTimer();
            cluster.configure(new Configuration(response.index(), response.term(), response.timestamp(), response.members()));
            future.complete(null);
          } else if (response.error() == null || response.error() == CopycatError.Type.NO_LEADER_ERROR) {
            cancelConfigureTimer();
            configureTimeout = cluster.getContext().getThreadContext().schedule(cluster.getContext().getElectionTimeout().multipliedBy(2), () -> configure(type, future));
          } else {
            cancelConfigureTimer();
            future.completeExceptionally(response.error().createException());
          }
        }
      });
    }
docs: Recursively reconfigures the cluster.