Browse Source

fix(mqtt): cap task_id at int32 max to prevent P1S dispatch stalls (#1042)

maziggy 1 month ago
parent
commit
d0f35e5d60
3 changed files with 26 additions and 6 deletions
  1. 1 0
      CHANGELOG.md
  2. 8 1
      backend/app/services/bambu_mqtt.py
  3. 17 5
      backend/tests/unit/services/test_bambu_mqtt.py

File diff suppressed because it is too large
+ 1 - 0
CHANGELOG.md


+ 8 - 1
backend/app/services/bambu_mqtt.py

@@ -3020,7 +3020,14 @@ class BambuMQTTClient:
             # validation" (unlike Studio, we don't have the file's real md5 here
             # without re-reading the upload, and sending a synthetic wrong digest
             # risks activation of md5 verification on some firmwares).
-            submission_id = str(int(time.time() * 1000))
+            # Cap at signed int32 max: P1S firmware (01.10.00.00) clamps oversized
+            # task identity fields to 2**31-1, so raw epoch-ms (13 digits, ~1.7e12)
+            # overflows and every submission ends up with the same task_id from
+            # the printer's perspective — the printer then treats a fresh dispatch
+            # as a continuation of the last FAILED job and never leaves IDLE (#1042).
+            # Modulo keeps uniqueness within a ~24-day wrap window; `or 1` guards
+            # the (astronomically unlikely) zero case since task_id=0 is rejected.
+            submission_id = str(int(time.time() * 1000) % 2_147_483_647 or 1)
 
             command = {
                 "print": {

+ 17 - 5
backend/tests/unit/services/test_bambu_mqtt.py

@@ -3480,17 +3480,29 @@ class TestStartPrintUniqueIdentityFields:
         assert first["project_id"] != second["project_id"]
 
     def test_submission_id_is_numeric_string(self, mqtt_client):
-        """ID format: digits-only string (epoch millis). Studio uses cloud
-        task IDs that are also numeric-looking strings; the DB column is
-        VARCHAR(64) and Bambuddy's own subtask_id parser treats '0'/'' as
-        absent — any valid digit string that isn't '0' is fine."""
+        """ID format: digits-only string. Studio uses cloud task IDs that are
+        also numeric-looking strings; the DB column is VARCHAR(64) and
+        Bambuddy's own subtask_id parser treats '0'/'' as absent — any valid
+        digit string that isn't '0' is fine."""
         mqtt_client.start_print("test.3mf")
         cmd = self._get_published_command(mqtt_client)
         assert cmd["task_id"].isdigit()
         assert int(cmd["task_id"]) > 0
-        # Must fit in VARCHAR(64); epoch-ms is 13 digits
         assert len(cmd["task_id"]) <= 64
 
+    def test_submission_id_fits_signed_int32(self, mqtt_client):
+        """Regression for #1042: P1S firmware clamps oversized task identity
+        fields to signed int32 max (2**31-1 = 2147483647). If we send raw
+        epoch-ms (~1.7e12), the printer sees a saturated constant on every
+        submission and treats fresh dispatches as continuations of the last
+        FAILED job — never leaves IDLE. Keep below 2**31.
+        """
+        mqtt_client.start_print("test.3mf")
+        cmd = self._get_published_command(mqtt_client)
+        assert int(cmd["task_id"]) < 2**31
+        assert int(cmd["project_id"]) < 2**31
+        assert int(cmd["subtask_id"]) < 2**31
+
     def test_unrelated_payload_fields_untouched(self, mqtt_client):
         """Regression guard: fix only touches identity fields; everything else
         (sequence_id, command verb, calibration defaults, profile_id) must be

Some files were not shown because too many files changed in this diff