@Test
  public void testLatchSizeN() {
    final int latchSize = 3;
    final String latchId = "testLatchSizeN";

    ExecutorService pool = Executors.newFixedThreadPool(3);
    Future f1 = pool.submit(getParticipantRunnable(latchSize, latchId, "participant1"));
    Future f2 = pool.submit(getParticipantRunnable(latchSize, latchId, "participant2"));
    Future f3 = pool.submit(getParticipantRunnable(latchSize, latchId, "participant3"));

    try {
      f1.get(30, TimeUnit.SECONDS);
      f2.get(30, TimeUnit.SECONDS);
      f3.get(30, TimeUnit.SECONDS);
    } catch (Exception e) {
      Assert.fail("failed to get future." + e.getLocalizedMessage());
    } finally {
      pool.shutdownNow();
    }
    try {
      List<String> latchParticipants =
          testZkUtils.getZkClient().getChildren(
              String.format("%s/%s_%s", KEY_BUILDER.getRootPath(), ZkProcessorLatch.LATCH_PATH, latchId));
      Assert.assertNotNull(latchParticipants);
      Assert.assertEquals(3, latchParticipants.size());
    } catch (Exception e) {
      Assert.fail("Failed to read the latch status from ZK directly" + e.getLocalizedMessage());
    }
  }
The ZkProcessorLatch uses a shared Znode as a latch. Each participant await existence of a target znode under the
shared latch, which is a persistent, sequential target znode with value (latchSize - 1). latchSize is the minimum
number of participants that need to join the latch.
samza-core/src/test/java/org/apache/samza/zk/TestZkProcessorLatch.java