Skip to content

A Kafka poison-pill head-of-line block problem - #790

Merged
Saadmrp1038 merged 8 commits into
SREGym:mainfrom
TheDeadcoder:feat/kafka_poison_pill_hol_block
May 29, 2026
Merged

A Kafka poison-pill head-of-line block problem#790
Saadmrp1038 merged 8 commits into
SREGym:mainfrom
TheDeadcoder:feat/kafka_poison_pill_hol_block

Conversation

@TheDeadcoder

Copy link
Copy Markdown
Contributor

Summary

This PR adds kafka_poison_pill_hol_block, which is a Kafka poison-pill head-of-line block problem

A common production incident for Kafka-based microservice platforms is poison pill. It is a single malformed record that a consumer cannot deserialize. Because order is preserved within a partition, that one record blocks every valid message behind it. The offset is never committed. Meanwhile the lag grows, and yet every pod still reports healthy. Real outages have been attributed to this, including a malformed record that blocked a payment pipeline for around 45 minutes. So far, I could not find fault of this kind in SREGym. A poison pill lives in the Kafka log, outside the control plane, so a restarted consumer replays the bad record. This PR adds that scenario.

Relevant References:
Conduktor - Dead Letter Topics: Handling Poison Pills
Redpanda - Reliable message processing with a dead letter queue
Lydtech Consulting - Kafka Poison Pill

Code changes

3 files are added and one is edited:

  • sregym/generators/fault/inject_kafka.py - fault injector. A self-contained producer and consumer are deployed into the astronomy-shop namespace, and one poison record is seeded into a dedicated topic at offset 20.
  • sregym/conductor/oracles/data_plane_progress.py - DataPlaneProgressOracle, the mitigation oracle. Data-plane progress is graded from the consumer's logs.
  • sregym/conductor/problems/kafka_poison_pill_hol_block.py - the problem definition.
  • sregym/conductor/problems/registry.py - one import and one registry entry (see registry.patch.md).

After the problem starts and the diagnosis stage opens, an interval of about 1 to 2 minutes should be allowed before investigation begins, so the stalled consumer and the growing lag are clearly visible.

Validation

uv run python tests/integration/validate_problem.py --problem kafka_poison_pill_hol_block

Expected behaviour

While the fault is active, the consumer logs repeat unprocessable record at offset=20, the committed offset stays at 20, and lag grows, while every pod remains Running and Ready. Diagnosis is scored by the existing LLM judge. The mitigation oracle prints its checks and ends with either a pass or a clear failure reason (offset not advanced past poison record, data loss: valid records skipped, or not restart-resistant). Results are written to the cli.py results panel, or to the run CSV when main.py is used. Inspection commands used here are:

kubectl logs deployment/orders-validator -n astronomy-shop --tail=20  # ... unprocessable record at offset=20 ...
kubectl get pods -n astronomy-shop -l app=orders-validator # 1 pod running
kubectl logs deployment/order-stream  -n astronomy-shop --tail=5   # producer still streaming

Mitigation

The expected fix is to move the consumer group past the poison record without dropping the valid messages queued behind it. Since an offset reset requires the group to have no active members, the consumer is stopped first, the group offset is reset to 21 (one past the poison), and the consumer is started again:

kubectl scale deployment/orders-validator -n astronomy-shop --replicas=0
# now need to wait ~60s so the broker evicts the stopped consumer and the group goes inactive
kubectl run kafka-admin --rm --restart=Never -n astronomy-shop \
  --image=apache/kafka:3.9.0 -- \
  /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server kafka:9092 \
  --group orders-validator --topic orders-fulfillment \
  --reset-offsets --to-offset 21 --execute

kubectl scale deployment/orders-validator -n astronomy-shop --replicas=1

The consumer resumes at offset 21, drains the backlog, and keeps pace with the producer. A plain restart is rejected, since the same offset is re-read and the stall returns. A reset to latest is rejected, since the valid backlog is skipped and counted as data loss.

@HacksonClark

Copy link
Copy Markdown
Member

After the problem starts and the diagnosis stage opens, an interval of about 1 to 2 minutes should be allowed before investigation begins, so the stalled consumer and the growing lag are clearly visible.

We should put this on a timer (ideally where we wait for a specific status) so that way we can run it automatically. I can't accept a problem if it requires manual intervention to run it as we need to get our evals fully autonomous.

@TheDeadcoder

Copy link
Copy Markdown
Contributor Author

After the problem starts and the diagnosis stage opens, an interval of about 1 to 2 minutes should be allowed before investigation begins, so the stalled consumer and the growing lag are clearly visible.

We should put this on a timer (ideally where we wait for a specific status) so that way we can run it automatically. I can't accept a problem if it requires manual intervention to run it as we need to get our evals fully autonomous.

You are right. I fixed it. Now there is no manual wait. Now, I used poll for the readiness check instead of manual wait.

@Saadmrp1038
Saadmrp1038 self-requested a review May 27, 2026 07:00
@Saadmrp1038 Saadmrp1038 added the problem Adding a new problem to the benchmark label May 27, 2026

@Saadmrp1038 Saadmrp1038 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheDeadcoder Thanks for the effort! This is a really interesting fault. The poison-pill HOL block is a great real-world scenario that's clearly distinct from the existing kafka_queue_problems. The oracle design is solid (outcome-based, not prescriptive). I left some inline comments below. Please ping me when you've addressed them.


Feel free to ping us if you have any questions or confusions!

Comment thread sregym/generators/fault/inject_kafka.py Outdated
Comment thread sregym/generators/fault/inject_kafka.py Outdated
Comment thread sregym/conductor/problems/registry.py
Comment thread sregym/generators/fault/inject_kafka.py
@TheDeadcoder
TheDeadcoder requested a review from Saadmrp1038 May 29, 2026 08:37
@Saadmrp1038

Copy link
Copy Markdown
Collaborator

/validate-problem kafka_poison_pill_hol_block

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Problem Validation

Status: 🟡 Running for kafka_poison_pill_hol_block

Deploying app → injecting fault → checking oracle → recovering → checking oracle.
Typical runtime is 5–15 minutes.

Live workflow run · commit 9cd0e890

@Saadmrp1038

Copy link
Copy Markdown
Collaborator

@TheDeadcoder works great now! Thanks for addressing my comments.
Congrats on your first PR merged here 🎉
Keep up the good work!

@Saadmrp1038
Saadmrp1038 merged commit 9bba32a into SREGym:main May 29, 2026
5 checks passed
@tianyin

tianyin commented May 29, 2026

Copy link
Copy Markdown
Contributor

@TheDeadcoder I assume you are from the UIUC+ program?

We are going to start the project very soon.

Could you join the SREGym Slack? We are going to mostly use that for discussion.

@Saadmrp1038

Copy link
Copy Markdown
Collaborator

@tianyin I added him.

@tianyin

tianyin commented May 29, 2026

Copy link
Copy Markdown
Contributor

:-O I searched "Nazmus" and failed -_-

And you are going with "Pial".

So I should use the last name to address colleagues in Bangladesh, right?

@Saadmrp1038

Copy link
Copy Markdown
Collaborator

@tianyin hehe. It differs from person to person what they prefer :3

ermias19 pushed a commit to ermias19/SREGym that referenced this pull request Jun 5, 2026
* oracle

* kafka_poison_pill_hol_block

* fix - validation

* poll for autonomous

* [fix] label dropped, Rolling-update race remove, rewritten Data-loss check

* fix ruff import order

---------

Co-authored-by: Saad Mohammad Rafid Pial <saadmrp222@gmail.com>
ermias19 pushed a commit to ermias19/SREGym that referenced this pull request Jun 5, 2026
* oracle

* kafka_poison_pill_hol_block

* fix - validation

* poll for autonomous

* [fix] label dropped, Rolling-update race remove, rewritten Data-loss check

* fix ruff import order

---------

Co-authored-by: Saad Mohammad Rafid Pial <saadmrp222@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

problem Adding a new problem to the benchmark

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants