Native asynchronous MQTT 3.1.1 client with QoS 0/1 and clean-session reconnect
./scripts/moon.sh build --target native
.venv/bin/python examples/mqtt_demo/demo.py./scripts/moon.sh run examples/mqtt_demo/cli --target native -- \
publish --host 127.0.0.1 -t lab/state -m ON --qos 1 --retain --stats
./scripts/moon.sh run examples/mqtt_demo/cli --target native -- \
subscribe --host 127.0.0.1 -t 'lab/#' --count 1 --timeout-ms 3000moon update
moon check --target native
moon test --target native
moon build --target nativemoon add Strangelight-Merser/moon-mqtt-clientasync fn main {
let config = @mqtt.Config::new("127.0.0.1", "my-moon-client")
@mqtt.with_client(config, async fn(client) {
let results = client.subscribe([
{ topic: "lab/temperature", qos: @mqtt.AtLeastOnce },
])
if results == [@mqtt.Granted(@mqtt.AtLeastOnce)] {
client.publish("lab/status", @utf8.encode("ready"),
qos=@mqtt.AtLeastOnce, retain=true)
}
// Consume Connected, Disconnected and MessageReceived events here.
// A long-running subscriber must continually drain next_event().
})
}| Result | What it establishes |
|---|---|
| QoS 0 publish returns | The transport write completed; no broker acknowledgement exists. |
| QoS 1 publish returns | A matching PUBACK arrived on that connection. It does not establish downstream processing or a physical action. |
| NotSent | A queued request failed before its write started. |
| OutcomeUnknown | A write began but the operation was not confirmed. Partial writes and lost ACKs are included. |
| Backpressure from a request | The send or inflight limit prevented accepting that request. |
| Event/control queue overflow | The client terminates with an error instead of silently dropping messages. |
python3 -m venv .venv
.venv/bin/pip install -r tests/integration/requirements.txt
# Install Mosquitto and OpenSSL using your OS package manager, then:
PYTHON=.venv/bin/python ./tests/integration/run.sh# Pinned official EMQX image: send/receive, subscription denial, restart recovery
./tests/emqx.sh
# 30-minute restart soak: 1 KiB QoS 1, concurrency 16, 100 disconnect cycles.
# The broker log is quiet by default and capped, so the run leaves bounded evidence.
MOONBIT_ASYNC_CHECK_FD_LEAK=1 .venv/bin/python tests/soak.py \
--duration 1800 --cycles 100 --artifacts tests/integration/artifacts/soakpub(all) suberror ClientError {
InvalidConfig(String)
ProtocolError(String)
NotConnected
Closed
Backpressure(String)
NotSent(String)
OutcomeUnknown(String)
ConnectionRefused(String)
ReconnectExhausted(String)
OperationTimeout(String)
WriteTimeout(String)
PingResponseTimeout(String)
} derive(Debug)type Clientasync fn Client::subscribe(self : Client, topics : Array[Subscription]) -> Array[SubscriptionResult]pub(all) struct ClientStats {
generation : Int
connected : Bool
business_queue_depth : Int
control_queue_depth : Int
event_queue_depth : Int
pending_requests : Int
reconnects : Int
disconnects : Int
unknown_outcomes : Int
last_disconnect : String?
}pub(all) struct Config {
host : String
port : Int
client_id : String
tls : TlsMode
username : String?
password : Bytes?
will : Will?
keep_alive_secs : Int
connect_timeout_ms : Int
operation_timeout_ms : Int
write_timeout_ms : Int
ping_response_timeout_ms : Int
send_capacity : Int
receive_capacity : Int
max_inflight : Int
max_packet_size : Int
reconnect_delay_ms : Int
max_reconnect_delay_ms : Int
reconnect_attempts : Int
control_capacity : Int
}fn Config::new(host : String, client_id : String, port? : Int, tls? : TlsMode, username? : String?, password? : Bytes?, will? : Will?, keep_alive_secs? : Int, connect_timeout_ms? : Int, operation_timeout_ms? : Int, write_timeout_ms? : Int, ping_response_timeout_ms? : Int, send_capacity? : Int, receive_capacity? : Int, max_inflight? : Int, max_packet_size? : Int, reconnect_delay_ms? : Int, max_reconnect_delay_ms? : Int, reconnect_attempts? : Int, control_capacity? : Int) -> ConfigInstall
Download zipNative asynchronous MQTT 3.1.1 client with QoS 0/1 and clean-session reconnect