code: @Procedure(mode = Mode.WRITE)
      @Description("apoc.periodic.rock_n_roll_while('some cypher for knowing when to stop', 'some cypher for iteration', 'some cypher as action on each iteration', 10000) YIELD batches, total - run the action statement in batches over the iterator statement's results in a separate thread. Returns number of batches and total processed rows")
      public Stream<LoopingBatchAndTotalResult> rock_n_roll_while(
              @Name("cypherLoop") String cypherLoop,
              @Name("cypherIterate") String cypherIterate,
              @Name("cypherAction") String cypherAction,
              @Name("batchSize") long batchSize) {
  
          Stream<LoopingBatchAndTotalResult> allResults = Stream.empty();
  
          Map<String,Object> loopParams = new HashMap<>(1);
          Object value = null;
  
          while (true) {
              loopParams.put("previous", value);
  
              try (Result result = db.execute(cypherLoop, loopParams)) {
                  value = result.next().get("loop");
                  if (!Util.toBoolean(value)) return allResults;
              }
  
              log.info("starting batched operation using iteration `%s` in separate thread", cypherIterate);
              try (Result result = db.execute(cypherIterate)) {
                  Stream<BatchAndTotalResult> oneResult =
                      iterateAndExecuteBatchedInSeparateThread((int) batchSize, false, false,0, result, params -> db.execute(cypherAction, params), 50, -1);
                  final Object loopParam = value;
                  allResults = Stream.concat(allResults, oneResult.map(r -> r.inLoop(loopParam)));
              }
          }
      }
docs: as long as cypherLoop does not return 0, null, false, or the empty string as 'value' do:
  
  invoke cypherAction in batched transactions being feeded from cypherIteration running in main thread
  
  @param cypherLoop
  @param cypherIterate
  @param cypherAction
  @param batchSize