private Boolean consumeClaimedIdPaylods(final ClaimedIdPayloads claimedIdPayloads) {
      final long claimedStamp = System.nanoTime();

      if (claimedIdPayloads.getIdPayloads().isEmpty()) {
        if (donePublishing.get()) {
          if (luaQ.getPublishedQSize() == 0) return Boolean.FALSE;
        }
        return Boolean.TRUE;
      }

      final byte[][] ids =
          claimedIdPayloads
              .getIdPayloads()
              .stream()
              .map(
                  idPayloads -> {
                    final byte[] idBytes = idPayloads.get(0);
                    final int id = Integer.parseInt(new String(idBytes, StandardCharsets.UTF_8));
                    publishClaimedStamps.get(id)[1] = claimedStamp;
                    return idBytes;
                  })
              .toArray(byte[][]::new);

      luaQ.removeClaimed(claimedIdPayloads.getClaimStamp(), ids);

      return Boolean.TRUE;
    }
    @Override
    public void run() {

      try {
        latch.await();
      } catch (final InterruptedException e) {
        throw Throwables.propagate(e);
      }

      luaQ.consume(this::consumeClaimedIdPaylods, consumeBatchSize);
    }
  public void run(final int numJobs, final int payloadSizeBytes, final int numConsumers) {

    luaQ.clear();

    final ExecutorService consumerExecutor = Executors.newFixedThreadPool(numConsumers);
    final List<Future<?>> consumerFutures = new ArrayList<>(numConsumers);
    final CountDownLatch startLatch = new CountDownLatch(1);
    final AtomicBoolean donePublishing = new AtomicBoolean(false);
    final Map<Integer, long[]> publishClaimedStamps = new HashMap<>(MapUtils.capacity(numJobs));
    for (int i = 0; i < numJobs; i++) {
      publishClaimedStamps.put(i, new long[2]);
    }

    for (int i = 0; i < numConsumers; i++) {

      if (jedisPublisherAndPrototype == null) {
        consumerFutures.add(
            consumerExecutor.submit(
                new Consumer(luaQ, startLatch, donePublishing, publishClaimedStamps, 1)));
        continue;
      }

      final LuaQ directConsumerQ =
          new LuaQ(
              new DirectJedisExecutor(
                  new Jedis(
                      jedisPublisherAndPrototype.getClient().getHost(),
                      jedisPublisherAndPrototype.getClient().getPort())),
              ThroughputBenchmark.class.getSimpleName());

      consumerFutures.add(
          consumerExecutor.submit(
              new Consumer(directConsumerQ, startLatch, donePublishing, publishClaimedStamps, 1)));
    }

    final byte[] payload = new byte[payloadSizeBytes];
    Arrays.fill(payload, (byte) 1);

    startLatch.countDown();

    for (int i = 0; i < numJobs; i++) {
      final byte[] id = String.valueOf(i).getBytes(StandardCharsets.UTF_8);
      final long publishClaimedStamp = System.nanoTime();
      luaQ.publish(id, payload);
      publishClaimedStamps.get(i)[0] = publishClaimedStamp;
    }

    donePublishing.set(true);
    for (final Future<?> consumerFuture : consumerFutures) {
      Futures.getUnchecked(consumerFuture);
    }

    consumerExecutor.shutdown();

    final long[] latencyNanos =
        publishClaimedStamps
            .values()
            .stream()
            .mapToLong(publishClaimedStamp -> publishClaimedStamp[1] - publishClaimedStamp[0])
            .sorted()
            .toArray();

    System.out.printf("Min latency %.2f (ms)%n", latencyNanos[0] / 1000000.0);
    System.out.printf("Max latency %.2f (ms)%n", latencyNanos[latencyNanos.length - 1] / 1000000.0);

    final long medianNanos = latencyNanos[latencyNanos.length / 2];
    System.out.printf("Median latency %.2f (ms)%n", medianNanos / 1000000.0);

    final double avgNanos = LongStream.of(latencyNanos).average().orElse(-1);
    System.out.printf("Average latency %.2f (ms)%n", avgNanos / 1000000);
  }