SyMqtt design decisions
SyMqtt was built with a core directive: Predictability and safety over magic features.
In industrial IoT and mission-critical distributed systems, hidden framework behaviors are dangerous. We intentionally excluded several seemingly attractive features to guarantee deterministic behavior and protect your hardware infrastructure.
1. No hidden auto-retries (order over “magic”)
Section titled “1. No hidden auto-retries (order over “magic”)”- The temptation: Automatically retrying a failed Request-Response call under the hood.
- The danger: In industrial automation, command ordering is critical. If a
Stop_Motorcommand times out due to a transient network glitch, and the framework silently retries it while the application has already issued a subsequentStart_Motor_New_Speedcommand, the operations can execute out of order at the broker level. This causes severe, hard-to-debug race conditions. - Our decision:
SyMqttreports failures instantly via timeouts. Resiliency strategies (retries, exponential backoffs, circuit breakers) must be explicitly managed by your business logic, where command sequence context is fully understood.
2. Post-connection immutability (safety over mutations)
Section titled “2. Post-connection immutability (safety over mutations)”- The temptation: Allowing users to dynamically inject, mutate, or delete channels and topics on
SyMqttBoxwhile the client is actively connected. - The danger: Runtime mutations introduce complex thread locking, memory overhead, and unpredictable state synchronization bugs across high-load background workers.
- Our decision: Topology configuration is strictly declarative during startup. If your infrastructure changes radically at runtime, the safe path is a controlled disconnection, re-configuration, and a clean re-connection. Predictable state is safe state.
3. Delimiter-based text envelopes (no heavy dependencies)
Section titled “3. Delimiter-based text envelopes (no heavy dependencies)”- The temptation: Embedding complex JSON, Protobuf, or MessagePack serializers inside the transport envelope parsing phase.
- The danger: Microcontrollers (Arduino, ESP32) frequently lack the memory or CPU power to process heavy objects natively, while backend microservices have wildly varying serialization standards.
- Our decision: The
SerialMessageconvention uses a high-speed, lightweight text delimiter scheme ([Id],[Contents]). TheContentsproperty is a raw string. If your system requires JSON or binary payloads, your application layer handles that execution in a single line of code, keeping the core transport engine dependencies at absolute zero.
4. Timeout-driven lifecycle (trusting the broker)
Section titled “4. Timeout-driven lifecycle (trusting the broker)”- The temptation: Purging all pending synchronous requests from the internal queue the exact millisecond a network disconnect event is intercepted.
- The danger: MQTT brokers often handle brief reconnections gracefully. If a connection drops for 500ms and restores itself immediately, a response might still arrive safely before the application’s timeout expires. Kill-on-disconnect would unnecessarily break “in-flight” requests that could have succeeded.
- Our decision: Time is the ultimate judge. Pending requests live or die strictly based on their configured
Timeout.