Skip to content

[FEAT] MQTT: apply with_qos to inbound subscriptions #268

Description

@lxsaah

Is your feature request related to a problem? Please describe.

with_qos on an inbound MQTT link has no effect. The value is stored in the link config, but both backends subscribe every inbound topic at QoS 1:

  • Native (rumqttc): native.rs subscribes with QoS::AtLeastOnce.
  • Embedded (mountain-mqtt): embedded/session.rs and embedded/tls.rs build every subscription with QualityOfService::Qos1.

A subscriber receives min(publish QoS, subscribe QoS), so:

  • with_qos(0): a high-rate telemetry link cannot opt out of acknowledgements. The broker still keeps state and waits for a PUBACK for every message.
  • with_qos(2): a QoS 2 publish still arrives at QoS 1, so it can be delivered twice after a reconnect. Only the native backend could honour QoS 2; mountain-mqtt rejects QoS 2 subscriptions.

Until #267, the MqttLinkExt::with_qos doc claimed "Inbound: the subscribe QoS". #267 corrects the doc and keeps the behaviour. Design 055 lists inbound subscribe QoS as a non-goal (§2).

Describe the solution you'd like

Subscribe each filter at the highest qos among the inbound links it stands for, default 1.

  • Since feat: wildcard inbound links (055) #267, one subscribed filter can stand for several links: Router::subscriptions() leaves out a filter another one covers, such as sensors/kitchen/temp under sensors/+/temp. The highest QoS among those links guarantees every covered link at least what it asked for.
  • The router therefore has to expose each subscribed filter's link configs. For example, subscriptions() could return Subscription { filter, links: Vec<Arc<[(String, String)]>> } instead of Arc<str>. Core does not interpret the config; the MQTT backends read qos.
  • The embedded backend caps at 1, and warn_unsupported_qos (today only outbound) also names each inbound route that asks for 2, once at build.
  • Both backends pass the per-filter QoS to their subscribe calls.

Tests:

  • A unit test that the highest qos wins and the default is 1.
  • An extension of the backend parity test: with with_qos(2) on a covered link, the native backend subscribes the covering filter at QoS 2 (the fake broker records the requested QoS) and the embedded backend at QoS 1.

Describe alternatives you've considered

  • Reject with_qos on inbound links at build(). Honest, but it removes a knob users reasonably expect from MQTT.
  • Subscribe each link's filter separately at its own QoS, without covering. Overlapping subscriptions deliver twice to MQTT 5 clients but once to MQTT 3.1.1 clients (measured against Mosquitto 2.0.18, 055 §3.1), so the two backends would disagree.

Additional context

  • The design text for this came from an earlier draft of 055 §5.7 ("Subscribe QoS"), removed when the scope was narrowed. See the history of docs/design/055-wildcard-inbound-links.md.
  • Related: feat: wildcard inbound links (055) #267 (wildcard inbound links).

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions