Skip to content

Offline queue retries permanently-rejected (400/500) mutations forever #24

Description

@fabracht

Summary

A queued mutation that the broker rejects permanently with a non-409 status is misclassified as transient and retried forever by the offline queue, never draining.

Mechanism

check_response (sync_engine.rs) maps broker status codes to errors: 401→SessionInvalid, 403→Ownership, 404→NotFound, 409→Conflict, and everything else → Error::Mqtt. The broker (mqdb-core transport.rs) returns:

  • Validation / SchemaViolation → 400 (BadRequest)
  • internal errors → 500

Both land in the catch-all → Error::Mqtt, and Error::is_transient() is true for Mqtt. In flush_consolidated, Err(err) if err.is_transient() => FlushOutcome::Keep, so a permanently-invalid queued mutation (e.g. a schema-invalid write) is retained and re-sent on every flush cycle indefinitely.

Why is_permanent_mutation does not catch it

Error::is_permanent_mutation matches only Error::Mqdb{ … } variants — errors from the local backend. The offline queue flushes to the remote, which never yields Error::Mqdb (its constraint violations come back as 409 → Conflict; its validation errors as 400 → Mqtt). So the classifier is unreachable on the flush path, and the intended "drop permanent failures" behavior never fires for remote-permanent rejections.

Options

  • Broker: use a distinct status code for permanent-non-conflict rejections so the client can classify them as permanent and drop.
  • Client: cap retry attempts per queued mutation, or treat a 400 (BadRequest) as permanent (drop after logging) rather than transient.

Pre-existing (not introduced by #22); surfaced while reviewing the conflict-rollback fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions