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)

Reply via email to