Federico Mariani created CAMEL-26808:
----------------------------------------
Summary: camel-azure-iothub: device-side consumer for
cloud-to-device messages, direct methods and desired-property updates
Key: CAMEL-26808
URL: https://issues.apache.org/jira/browse/CAMEL-26808
Project: Camel
Issue Type: New Feature
Components: camel-azure
Reporter: Federico Mariani
The camel-azure-iothub component proposed in [PR
#29489|https://github.com/apache/camel/pull/29489] (CAMEL-22624) is
producer-only. Camel connects to IoT Hub as a device (Azure IoT device SDK
{{DeviceClient}}) and sends telemetry and reported properties on the device's
behalf. The return path is missing: commands and configuration changes from the
cloud cannot reach the devices Camel represents.
h3. Proposal
A consumer built on the device SDK the producer already uses:
* *Cloud-to-device (C2D) messages*: {{DeviceClient.setMessageCallback}}.
InOnly; success completes the message ({{COMPLETE}}), failure abandons
({{ABANDON}}, redelivered) or rejects it ({{REJECT}}, dead-lettered),
configurable.
* *Direct methods*: {{subscribeToMethods}}. InOut; the reply body becomes the
method payload, the status comes from a header (default 200).
* *Desired properties*: {{subscribeToDesiredProperties}}. InOnly, one exchange
per update.
h3. Constraints
These come from reading the iot-device-client 2.5.0 source and the IoT Hub
documentation; they were not verified against a live hub.
* *MQTT ignores the ack result.* {{MqttIotHubConnection.sendMessageResult}}
always acknowledges ("The only ack that can be sent in MQTT is COMPLETE"). Over
MQTT, the producer's default protocol, a C2D message whose exchange failed is
acknowledged and lost. Only AMQPS supports ABANDON and REJECT. Document this,
and warn when a C2D consumer runs over MQTT.
* *One connection per device.* IoT Hub drops the existing connection when a new
one opens for the same device id (error 400027). A producer and a consumer for
the same device must share one {{DeviceClient}}: the pool has to be
component-scoped and keyed on the identity in the connection string, and a
client held by a consumer must never be evicted.
* *Register callbacks before {{open()}}.* The {{setMessageCallback}} javadoc
says messages may be missed if it is set after opening. A client already opened
by a producer has to be reopened when a consumer attaches.
* *The C2D callback must not throw.* If it throws, no ack is sent and the
message stays in IoT Hub until it expires, which blocks further C2D delivery to
that device. Every failure has to become an ack result.
* *One receive thread per client.* C2D, direct-method and desired-property
callbacks run one after another on the same thread, and the ack and the method
reply are returned synchronously. A slow C2D route delays direct-method
replies, and the caller of a direct method has a timeout.
* *Direct-method reply serialisation.* The SDK serialises the reply payload
with Gson {{toJsonTree}}, so a JSON object held in a String body is sent as a
quoted JSON string. The consumer has to parse it into a {{JsonElement}} first.
* *Missed desired-property updates.* Notifications only arrive while the device
is connected. The consumer should read the twin on every (re)connect to resync.
h3. Depends on
The pool changes requested in the PR #29489 review: a component-scoped pool,
leases so the evictor never closes a client in use, and a pool key taken from
the device identity.
_Claude Code on behalf of Croway_
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)