Skip to content

fix(serverust-events): silent Kafka ack loss and SQS DLQ redelivery loop - #22

Merged
JaimeJunr merged 6 commits into
mainfrom
cursor/critical-bug-investigation-0d26
Sep 13, 2026
Merged

JaimeJunr merged 6 commits into
mainfrom
cursor/critical-bug-investigation-0d26

Conversation

@cursor

@cursor cursor Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Weekly critical-bug scan found three high-severity correctness issues in serverust-events (beyond the already-merged SQS silent-ack and backoff panic fixes).

Bugs fixed

1. EventRouter DLQ + Lambda SQS — infinite redelivery

Impact: After retries exhaust and DLQ publish succeeds, wrap_with_retry still returned Err, so SqsBroker reported batchItemFailures and Lambda never deleted the source message — poison-message loop with duplicate DLQ writes.

Root cause: DlqLayer returns Ok(()) after successful DLQ routing; EventRouter did not.

Fix: Return Ok(()) when broker.publish(dlq_topic, …) succeeds.

2. LambdaBroker — silent Kafka message loss

Impact: Records whose topic had no subscribed handler were skipped while the invocation returned Ok(()), causing Lambda to commit offsets without processing.

Root cause: continue on empty handler list (pre-#12 SQS analogue).

Fix: Return BrokerError::Subscribe when no handler is registered for the record topic.

3. KafkaBroker::dispatch — silent no-op

Impact: Same class as (2) for long-running consumers that commit offset on Ok(()).

Fix: Return error when no handlers match msg.topic.

Validation

  • cargo test -p serverust-events --features sqs --test sqs_consumer --test lambda_broker
  • cargo test -p serverust-events --features "sqs in-memory" --test retry_policy

Not fixed (lower confidence / larger change)

  • subscribe_publish + with_retry re-runs user handler when only publish fails (duplicate side effects) — needs publish-only retry split.

Changelog

Updated [Unreleased] with the three fixes.

Open in Web View Automation 

…SQS Lambda

- EventRouter::with_dlq retorna Ok após publish bem-sucedido no DLQ
  (alinha com DlqLayer; evita redelivery infinito no Lambda ESM)
- LambdaBroker e KafkaBroker::dispatch erram quando não há handler
  inscrito, em vez de no-op que commitaria offset/ack implicitamente
- Testes de regressão para os três caminhos

Co-authored-by: Jaime Basso <JaimeJunr@users.noreply.github.com>
JaimeJunr and others added 3 commits September 13, 2026 00:31
…kers

Default WarnAndIgnore preserves 0.3.x skip (now with tracing::warn!).
Error returns BrokerError::Subscribe with received and registered topics.

EventRouter logs handler+DLQ errors via tracing::error! when DLQ publish
fails, instead of eprintln! of the DLQ error only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-events

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@JaimeJunr

Copy link
Copy Markdown
Owner

Revisado e ajustado. O bug 1 (loop de redelivery na DLQ) era correção pura e ficou como estava. Os bugs 2 e 3 foram reescritos como política configurável, porque o comportamento que o PR removia não era acidental — ignorar record de tópico sem handler estava documentado no doc comment e coberto por teste em broker/lambda.rs e tests/lambda_broker.rs. Trocar por erro duro quebraria quem usa subscription por padrão ou fan-out, e viraria poison-loop num consumer long-running.

Mudanças

UnhandledTopicPolicy (serverust-events/src/broker/mod.rs):

  • WarnAndIgnoredefault, preserva o comportamento 0.3.x. Ganho real mesmo no default: o skip era totalmente silencioso, agora emite tracing::warn! com o tópico.
  • Error — o comportamento que o PR propunha, agora opt-in via with_unhandled_topic_policy(...). A mensagem cita o tópico recebido e a lista de tópicos com handler registrado.

Aplicado em LambdaBroker e KafkaBroker::dispatch, com os doc comments atualizados. Os testes que documentavam o skip voltaram e seguem verdes no default; os testes de erro agora configuram Error explicitamente.

Lacuna do bug 1 fechada: quando o publish na DLQ falha, o erro ia só pra eprintln!. Virou tracing::error! com os dois erros no contexto (handler + DLQ), mais teste cobrindo o caminho.

Nota de dependência: tracing deixou de ser opcional em serverust-events (era só sob a feature sqs) — a policy e o log da DLQ rodam em código sem sqs. Registrado no CHANGELOG.

Validação local (por crate, serial):

cargo test -p serverust-events --features sqs --test lambda_broker --test sqs_consumer  →  6 + 15 ok
cargo test -p serverust-events --features "sqs in-memory" --test retry_policy          →  8 ok
cargo clippy -p serverust-events --features sqs --all-targets -- -D warnings           →  limpo
cargo fmt --check                                                                       →  ok
cargo tree -p serverust-core | grep -c kafka\|event  →  0   (invariante preservada)
cargo tree -p hello-world  | grep -c kafka\|dynamo   →  0   (invariante preservada)

⚠️ Não validado: --test kafka_broker_dispatch exige --features kafka, e librdkafka não compila nesta máquina (falta curl/curl.h — libcurl headers ausentes no sistema). O caminho KafkaBroker::dispatch foi revisado por código, não executado. Precisa de CI ou de uma máquina com as headers antes do merge.

🤖 Generated with Claude Code

Conflito de CHANGELOG resolvido por união: Added do PR mais os itens
de Changed dos dois lados.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

@JaimeJunr
JaimeJunr marked this pull request as ready for review September 13, 2026 01:22
Copilot AI lite review requested due to automatic review settings September 13, 2026 01:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Conflito de CHANGELOG resolvido por união das duas entradas em Fixed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

@JaimeJunr
JaimeJunr merged commit 5ee8752 into main Sep 13, 2026
13 of 14 checks passed
@JaimeJunr
JaimeJunr deleted the cursor/critical-bug-investigation-0d26 branch September 13, 2026 01:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants