AlgoMaster Logo

Lab: Run an Order Pipeline End to End

21 min readUpdated September 13, 2026
Listen to this chapter
Unlock Audio

In this lab, you publish order events to one broker and test four behaviors: records remain after reads; groups track progress independently; a restarted consumer resumes from its committed offset; and a new group can replay records Kafka still retains. You use only the console tools bundled in the apache/kafka:4.3.1 image, so you do not write client code.

Use the following topic and event batches. The topic is orders.placed with three partitions. Batch 1 holds six OrderPlaced events for orders ord-1042 through ord-1047, batch 2 holds three more for ord-1048 through ord-1050, and you publish each batch exactly once. With nine records in the topic, every LOG-END-OFFSET total, every lag value, and every replay count has one correct answer you can check your observations against.

Learning Objectives

  • Start the single-node KRaft broker and confirm readiness with a topic listing and a metadata quorum check.
  • Create a three-partition topic and publish keyed records with the console producer.
  • Read the partition and offset of each printed record and explain why equal keys share a partition.
  • Run two consumer groups on one topic and show that both receive every record.
  • Read CURRENT-OFFSET, LOG-END-OFFSET, and LAG from a group description and explain what each value measures.
  • Stop a consumer, grow its lag, and show that a restart resumes from the committed offset without repeating older records.
  • Replay a topic from the beginning with a new group without changing any other group's position.
  • Reset the local broker and explain what happened to the stored records.

Time and Environment

  • Setup and Phase 1: 15 minutes
  • Phases 2 and 3: 30 minutes
  • Phases 4 and 5: 30 minutes
  • Phase 6 and report: 30 minutes

Environment: E1, the single combined broker and controller in a container named kafka-local. Docker runs on your host. Every Kafka tool runs inside the container through docker exec; the only host files are the event batches and your observations. Open three Bash-compatible terminals: Terminal A for the order-reporting consumer, Terminal B for the order-fulfillment consumer, and Terminal C for everything else.

Safety Boundaries

  • Use only the container named kafka-local. Do not point any command at another Kafka cluster.
  • Phase 6 deletes the container and every record in it. Save your observation files before you run it.
  • Publish each batch file once. A second run adds duplicate event IDs and breaks the counts in the acceptance checks.

Project Layout

Create:

Run every command from kafka-labs/order-pipeline/ so the producer's relative file paths resolve.

Setup: Event Batches

Each line in a batch file is a key, a pipe character, and a JSON value, in the format the console producer accepts when you enable key parsing. Create events/batch-1.txt:

Create events/batch-2.txt:

Keep each event on one line with no blank lines; the producer treats every line as one record.

Phase 1: Start the Broker and Verify Readiness

If a kafka-local container already exists from the chapters, remove it first so the lab starts from a known state: docker stop --time 30 kafka-local followed by docker rm -v kafka-local. Then start a fresh broker in Terminal C:

Confirm the container is running and check the tail of its logs:

Now ask Kafka itself. A topic listing that returns with exit status 0 proves the broker answers requests, and the quorum check proves the controller side is up:

Record both outputs in observations/01-readiness.txt.

What you should see: the container status is Up, the topic listing prints nothing because no topics exist yet, and the quorum output names node 1 as the leader with a cluster ID. If the listing fails with a connection error, the broker may still be starting; wait and retry.

Phase 2: Create the Topic and Publish Batch 1

Create orders.placed with three partitions. The replication factor must be 1 because there is one broker:

Describe it and save the output as observations/02-topic.txt:

Publish batch 1. The -i flag keeps standard input open so the producer can read the file, parse.key=true splits each line at the first pipe, and --sync with acks=all waits for the broker to acknowledge each write before sending the next:

The producer exits quietly on success. Do not run it again.

What you should see: the describe output shows PartitionCount: 3, ReplicationFactor: 1, and three partition rows numbered 0, 1, and 2, each with Leader: 1, Replicas: 1, and Isr: 1. No consumer is running yet, so nothing prints the records. Kafka has already stored them, and the next phase proves it.

Phase 3: Read with Two Consumer Groups

Start the reporting consumer in Terminal A:

Start the fulfillment consumer in Terminal B with the same command, changing only the group to order-fulfillment. Leave both running.

Each group has one member, so that member receives all three partition assignments. Kafka tracks a separate committed offset for each group and partition; watch for that separation in the group descriptions.

Once both terminals have printed records, describe both groups from Terminal C and save the output as observations/03-two-groups.txt:

Also write down the partition and offset Terminal A printed for each key, and confirm Terminal B printed the same values.

What you should see: both terminals print the same six records at the same partitions and offsets, because they read the same stored log. Each group description has three rows, one per partition. In every row CURRENT-OFFSET equals LOG-END-OFFSET and LAG is 0, and the three LOG-END-OFFSET values add up to 6. The split across partitions depends on how the keys hash; record it rather than predicting it. If a CURRENT-OFFSET still trails, wait for the next auto-commit and describe again.

Phase 4: Stop One Consumer, Grow Its Lag, Resume It

Press Ctrl-C in Terminal A to stop the order-reporting consumer. Leave Terminal B running. Describe order-reporting from Terminal C; the committed offsets survive the stop.

Publish batch 2:

Wait until Terminal B has printed all three new records and its next auto-commit makes order-fulfillment’s lag zero. Then describe both groups and save both outputs as observations/04-reporting-stopped.txt.

What you should see: Terminal B prints the three new records as they arrive. The order-reporting description reports that the group has no active members, its CURRENT-OFFSET values are unchanged from Phase 3 and still add up to 6, its LOG-END-OFFSET values add up to 9, and its LAG values add up to 3. The order-fulfillment description shows LOG-END-OFFSET totaling 9 with every LAG back at 0. Stopping reporting did not stop fulfillment’s processing.

Now restart the consumer in Terminal A with the exact Phase 3 command, including --from-beginning. Wait until the next auto-commit makes reporting’s lag zero, describe both groups again, and save both outputs as observations/04-reporting-resumed.txt.

What you should see: Terminal A prints only the batch-2 keys ord-1048, ord-1049, and ord-1050. The six batch-1 records do not print again, even though the command says --from-beginning, because the group has a valid committed offset for every partition and that offset wins. After the commit, order-reporting shows LAG of 0 on all three rows and CURRENT-OFFSET totaling 9.

Phase 5: Replay Everything with a New Group

Neither running group can show the whole history again without moving its position. A brand-new group can. From Terminal C, run a consumer in the group first-orders-reader, which has never committed anything, and let it exit after nine records:

Save the nine printed lines as observations/05-replay.txt, then describe all three groups and append those outputs. Finally, look at where the broker keeps these records on disk:

What you should see: the replay prints nine records, one per event ID from evt-7001 to evt-7009, at the same partitions and offsets Terminals A and B reported earlier. Records from different partitions may interleave; within one partition, offsets ascend. The order-reporting and order-fulfillment descriptions are unchanged by the replay. The log directory listing contains orders.placed-0, orders.placed-1, and orders.placed-2, one directory per partition, alongside a set of __consumer_offsets- directories where the broker stores the committed offsets of all three groups. No producer republished the records, and reading the records a third time did not remove them.

Phase 6: Reset and Confirm the Data Is Gone

Press Ctrl-C in Terminals A and B. Then stop and remove the container:

Start a fresh broker with the Phase 1 docker run command, wait until the topic listing succeeds, then list topics, list consumer groups, and list the log directory. Save all three outputs as observations/06-reset.txt:

What you should see: the topic listing is empty, the group listing is empty, and the log directory has no orders.placed- directories. Describing orders.placed fails with an error saying the topic does not exist. The records lived in the container's filesystem under /tmp/kraft-combined-logs, and docker rm -v deleted that filesystem. A stop and start would have kept everything; removal did not.

Required Deliverables

  • events/batch-1.txt and events/batch-2.txt as published.
  • The seven observation files listed in the project layout, each containing the raw command output for its phase.
  • A key-to-partition table covering all nine keys, with the offset each key received.
  • report.md answering these questions:
    1. Why did order-fulfillment's lag return to 0 while you had stopped order-reporting and published batch 2?
    2. Why did the restarted order-reporting consumer skip the batch-1 records even though its command included --from-beginning?
    3. Suppose a traditional work queue had carried these events instead, with order-reporting and order-fulfillment as two workers on one queue. What would each worker have received from batch 1, and what would first-orders-reader have been able to read in Phase 5?
    4. Where did the nine records and the three groups' committed offsets live, and which command destroyed them?
    5. Records in the same partition have a fixed relative order. Records in different partitions do not. Give one example of each from your table.

Acceptance Checks

  • observations/01-readiness.txt contains a quorum status that names node 1 as leader.
  • observations/02-topic.txt shows PartitionCount: 3, ReplicationFactor: 1, and partitions 0, 1, 2 each with Leader: 1.
  • observations/03-two-groups.txt shows three rows per group, LAG of 0 in all six rows, and LOG-END-OFFSET values summing to 6 for each group.
  • observations/04-reporting-stopped.txt shows order-reporting with no active members and LAG summing to 3, and order-fulfillment with LAG summing to 0 and LOG-END-OFFSET summing to 9.
  • observations/04-reporting-resumed.txt shows order-reporting with LAG of 0 on all rows and CURRENT-OFFSET summing to 9.
  • observations/05-replay.txt contains exactly nine record lines, each event ID from evt-7001 through evt-7009 appears once, and the order-reporting and order-fulfillment descriptions match the resumed file.
  • observations/06-reset.txt shows an empty topic list and an empty group list.
  • The key-to-partition table lists nine keys, and every partition number is 0, 1, or 2.
  • report.md answers all five questions with reference to values in the observation files.

Grading Rubric

AreaPoints
Broker readiness evidence10
Topic creation and keyed publishing15
Two-group read and offset description20
Stop, lag growth, and resume evidence20
Replay with a new group and on-disk evidence10
Reset and storage explanation10
Report answers15
Total100

Optional Extensions

  • Start a second consumer in order-reporting in a fourth terminal, describe the group, and record how the three partitions split between the two members.
  • Publish one more event with the key ord-1042 and confirm it lands in the same partition as the first ord-1042 record.
  • Replay partition 0 alone with --partition 0 --offset 0 and no group, and compare with the group-based replay.
  • Before Phase 6, run docker stop and docker start instead of removal, then describe the topic and groups to show that both survive a restart.
  • Publish batch 2 a second time on purpose, replay with another new group, and find the duplicate event IDs at different offsets.

Cleanup

Stop any running console consumers with Ctrl-C, then remove the broker:

Verify that nothing remains:

The listing should show no container. The image stays downloaded for later modules. Keep the kafka-labs/order-pipeline/ folder; it is your submission.

Summary

You published nine keyed records once and read them through two live groups, a restarted consumer, and a replay group that started from offset 0. The group descriptions gave you the numbers behind the module's claims. LOG-END-OFFSET measured the log, CURRENT-OFFSET measured one group's committed position, and LAG was the gap between them. Publishing batch 2 increased order-reporting's lag while it was stopped. order-fulfillment kept reading and returned to zero lag.

The restart showed that a valid committed offset takes precedence over --from-beginning, and the replay showed that reading never removes anything. Kafka stored the records in files under /tmp/kraft-combined-logs, next to the __consumer_offsets partitions holding each group's progress, and they lasted exactly as long as the container that held them. A work queue would have handed each batch-1 event to one of the two workers and forgotten it on acknowledgment; Kafka kept the log and let every group decide where to stand in it.