code: public static ICompletableFuture<Object> invokeOnStableClusterSerial(NodeEngine nodeEngine,
                                                                           Supplier<? extends Operation> operationSupplier,
                                                                           int maxRetries) {
  
          ClusterService clusterService = nodeEngine.getClusterService();
          if (!clusterService.isJoined()) {
              return new CompletedFuture<Object>(null, null, new CallerRunsExecutor());
          }
  
          RestartingMemberIterator memberIterator = new RestartingMemberIterator(clusterService, maxRetries);
  
          // we are going to iterate over all members and invoke an operation on each of them
          InvokeOnMemberFunction invokeOnMemberFunction = new InvokeOnMemberFunction(operationSupplier, nodeEngine,
                  memberIterator);
          Iterator<ICompletableFuture<Object>> invocationIterator = map(memberIterator, invokeOnMemberFunction);
  
          ILogger logger = nodeEngine.getLogger(ChainingFuture.class);
          ExecutionService executionService = nodeEngine.getExecutionService();
          ManagedExecutorService executor = executionService.getExecutor(ExecutionService.ASYNC_EXECUTOR);
  
          // ChainingFuture uses the iterator to start invocations
          // it invokes on another member only when the previous invocation is completed (so invocations are serial)
          // the future itself completes only when the last invocation completes (or if there is an error)
          return new ChainingFuture<Object>(invocationIterator, executor, memberIterator, logger);
      }
docs: Invoke operation on all cluster members.
  
  The invocation is serial: It iterates over all members starting from the oldest member to the youngest one.
  If there is a cluster membership change while invoking then it will restart invocations on all members. This
  implies the operation should be idempotent.
  
  If there is an exception - other than {@link com.hazelcast.core.MemberLeftException} or
  {@link com.hazelcast.spi.exception.TargetNotMemberException} while invoking then the iteration
  is interrupted and the exception is propagated to the caller.