Skip to content

Commit 12156e5

Browse files
cartertinneyCopilot
andcommitted
fix: adopt Paho MQTT v2 callbacks
Migrate transport callbacks to Paho's version 2 API and classify connection and disconnect reasons by their documented semantics. Propagate broker-rejected SUBACKs through operation tracking, including early acknowledgements, and leave reconnect timing to the SDK. Remove obsolete reconnect-delay and private thread workarounds now that Paho 2.1 is required. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent fefdb59 commit 12156e5

7 files changed

Lines changed: 580 additions & 545 deletions

File tree

‎azure-iot-device/azure/iot/device/common/mqtt_transport.py‎

Lines changed: 128 additions & 151 deletions
Large diffs are not rendered by default.

‎azure-iot-device/azure/iot/device/common/pipeline/pipeline_stages_mqtt.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,15 @@ def on_complete(cancelled=False):
283283
logger.debug("{}({}): subscribing to {}".format(self.name, op.name, op.topic))
284284

285285
@pipeline_thread.invoke_on_pipeline_thread_nowait
286-
def on_complete(cancelled=False):
286+
def on_complete(cancelled=False, error=None):
287287
if cancelled:
288288
op.complete(
289289
error=pipeline_exceptions.OperationCancelled(
290290
"Operation cancelled before SUBACK received"
291291
)
292292
)
293+
elif error is not None:
294+
op.complete(error=error)
293295
else:
294296
logger.debug(
295297
"{}({}): SUBACK received. completing op.".format(self.name, op.name)

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ classifiers = [
2828
dependencies = [
2929
"deprecation>=2.1.0,<3.0.0",
3030
"janus",
31-
"paho-mqtt>=2.0.0,<3.0.0",
31+
"paho-mqtt>=2.1.0,<3.0.0",
3232
"PySocks",
3333
"requests>=2.32.3,<3.0.0",
3434
"requests-unixsocket>=0.4.1",

‎tests/unit/common/pipeline/test_pipeline_stages_mqtt.py‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ def test_complete(self, mocker, stage, op):
602602
assert op.error is None
603603

604604
@pytest.mark.it(
605-
"Completes the operation with an OperationCancelled error upon cancellation of the MQTT unsubscribe by the MQTTTransport"
605+
"Completes the operation with an OperationCancelled error upon cancellation of the MQTT publish by the MQTTTransport"
606606
)
607607
def test_complete_with_cancel(self, mocker, stage, op):
608608
# Begin publish
@@ -639,7 +639,7 @@ def op(self, mocker):
639639
)
640640

641641
@pytest.mark.it("Performs an MQTT subscribe via the MQTTTransport")
642-
def test_mqtt_publish(self, mocker, stage, op):
642+
def test_mqtt_subscribe(self, mocker, stage, op):
643643
stage.run_op(op)
644644
assert stage.transport.subscribe.call_count == 1
645645
assert stage.transport.subscribe.call_args == mocker.call(
@@ -662,10 +662,23 @@ def test_complete(self, mocker, stage, op):
662662
assert op.error is None
663663

664664
@pytest.mark.it(
665-
"Completes the operation with an OperationCancelled error upon cancellation of the MQTT unsubscribe by the MQTTTransport"
665+
"Completes the operation with an error received from the MQTT subscribe callback"
666+
)
667+
def test_complete_with_error(self, stage, op, arbitrary_exception):
668+
stage.run_op(op)
669+
670+
assert not op.completed
671+
672+
stage.transport.subscribe.call_args[1]["callback"](error=arbitrary_exception)
673+
674+
assert op.completed
675+
assert op.error is arbitrary_exception
676+
677+
@pytest.mark.it(
678+
"Completes the operation with an OperationCancelled error upon cancellation of the MQTT subscribe by the MQTTTransport"
666679
)
667680
def test_complete_with_cancel(self, mocker, stage, op):
668-
# Begin unsubscribe
681+
# Begin subscribe
669682
stage.run_op(op)
670683

671684
assert not op.completed
@@ -699,7 +712,7 @@ def op(self, mocker):
699712
)
700713

701714
@pytest.mark.it("Performs an MQTT unsubscribe via the MQTTTransport")
702-
def test_mqtt_publish(self, mocker, stage, op):
715+
def test_mqtt_unsubscribe(self, mocker, stage, op):
703716
stage.run_op(op)
704717
assert stage.transport.unsubscribe.call_count == 1
705718
assert stage.transport.unsubscribe.call_args == mocker.call(
@@ -739,7 +752,7 @@ def test_complete_with_cancel(self, mocker, stage, op):
739752
@pytest.mark.it(
740753
"Completes the operation using the exception that was raised, if an exception was raised from the MQTTTransport"
741754
)
742-
def test_publish_error(self, stage, op, arbitrary_exception):
755+
def test_unsubscribe_error(self, stage, op, arbitrary_exception):
743756
stage.transport.unsubscribe.side_effect = arbitrary_exception
744757

745758
stage.run_op(op)

0 commit comments

Comments
 (0)