Skip to content

feat(mqtt): expose write retransmission as WRITE_MAX_ATTEMPTS - #64

Merged
QuiteYellow merged 1 commit into
mainfrom
feat/bridge-write-max-attempts
Aug 23, 2026
Merged

feat(mqtt): expose write retransmission as WRITE_MAX_ATTEMPTS#64
QuiteYellow merged 1 commit into
mainfrom
feat/bridge-write-max-attempts

Conversation

@QuiteYellow

Copy link
Copy Markdown
Owner

#54 added write_max_attempts to DtlsCoapSession and left it off, on the argument that retransmitting into an appliance already dropping under load turns one lost write into several, and that RFC 7252 §4.5 dedupe is unverified on RT-OCF. Turning it on is meant to follow a measurement on real hardware.

The flag could only be set when a session was built, and session_once() did not set it. The reference bridge is the one deployment that can take that measurement, and it was the only one that could not reach the switch. I said as much on #54, so this is my half.

What this does

WRITE_MAX_ATTEMPTS joins SharedConfig beside the other int knobs and reaches the session. It defaults to 1, a single send and today's behaviour, so a bridge that never sets it is unchanged. docker-compose.yml already passes .env through with env_file, so no compose edit is needed on the host.

Process-wide, matching HEALTH_INTERVAL_S and PING_INTERVAL_S. Per-appliance would let a measurement target just the device dropping writes, and that is an easy follow-up if it turns out to be wanted.

No clamping in the bridge. A non-numeric value stops the process at startup the way MQTT_PORT does, and 0 is floored by the library's own max(1, int(...)).

Tests

Five, covering the default, the env var, a non-numeric value raising at startup, the kwarg reaching DtlsCoapSession(...), and the call site naming the SharedConfig field so the two stay wired together. Each was checked against a mutant: dropping the kwarg, flipping the default to 3, hardcoding the env read, and substituting a literal at the call site are all caught. Full suite 426.

On hardware

Deployed to the reference bridge, one dryer and one oven. The container was running a tree that predated #54, so this run soaks that merge as well.

Start to seeded in 9s and 11s. Both appliances went push_active → online, sweeps completed, and the knob was read back inside the running container: SharedConfig at 1, the call site wired, and the kwarg arriving at the real DtlsCoapSession(...) call at 1, then at 3 with WRITE_MAX_ATTEMPTS=3 in the environment.

Steady-state windows against the pre-deploy baseline on the same container, discarding the partial window containing the connect:

windows ok err ping-fail p_max timeouts
dryer before 45 92-95 0 0 224-1211ms 0
dryer after 8 93-96 0 0 277-1063ms 0
oven before 45 211-232 1 0 1854-3288ms 1
oven after 8 221-229 0 0 1889-2611ms 0

Both sit inside their baseline ranges.

mqtt_demo/ is outside the distributed package, so none of this reaches the wheel.

#54 added write_max_attempts to DtlsCoapSession, off by default, on the
argument that retransmitting into an appliance already dropping under
load turns one lost write into several and that RFC 7252 §4.5 dedupe is
unverified on RT-OCF. Turning it on is meant to follow a measurement.

The flag was constructor-only and session_once() did not pass it, so the
reference bridge was the one deployment that could take that measurement
and the only one that could not reach the switch.

WRITE_MAX_ATTEMPTS now sits in SharedConfig beside the other int knobs
and reaches the session. It defaults to 1, which is a single send and
today's behaviour, so a bridge that never sets it is unchanged.
docker-compose passes .env through with env_file, so this needs no
compose edit on the host.

Tests cover the default, the env var, a non-numeric value stopping the
process at startup the way the other int knobs do, and the call site
naming the SharedConfig field so the two stay wired together.
@QuiteYellow
QuiteYellow merged commit d4d3e12 into main Aug 23, 2026
8 checks passed
@QuiteYellow
QuiteYellow deleted the feat/bridge-write-max-attempts branch August 23, 2026 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant