Give the Influx and MQTT nodes their two missing knobs

The Influx client was built with no timeout, so every query and write fell
through to influxdb-client's own 10 s default — invisible to a flow and
unchangeable. The param is in seconds like its peers; the client counts in
milliseconds, so the call sites convert.

The publisher backlog was a module constant, read once at import. It is the
depth at which the oldest payload is dropped and the node goes degraded, and
a node that bursts wants more than one that trickles, so it moves to Params
and is read where the queue is built.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1moruzue2kTJd3uVisgNk
This commit is contained in:
2026-08-28 11:52:43 +02:00
co-authored by Claude Opus 5
parent 192999f178
commit f00045d6b6
4 changed files with 117 additions and 8 deletions
+41
View File
@@ -197,6 +197,47 @@ def test_a_flux_request_is_run_rather_than_written(monkeypatch):
assert out == {"answer": {"rows": [], "range_s": 3600}}
def test_the_configured_timeout_reaches_the_influx_client(monkeypatch):
"""The client counts in milliseconds; the param is seconds like its peers."""
import influxdb_client
from fluksio.flow.nodes import InfluxDbNode
seen: dict = {}
class FakeClient:
def __init__(self, **kwargs):
seen.update(kwargs)
def __enter__(self):
return self
def __exit__(self, *_):
return False
def query_api(self):
return self
def query(self, *_, **__):
return []
monkeypatch.setattr(influxdb_client, "InfluxDBClient", FakeClient)
node = InfluxDbNode(
provides=[MessageSpec(name="answer", dtype=DType.JSON)],
params={
"url": "http://influx",
"token": "t",
"org": "o",
"bucket": "b",
"timeout": 2.5,
},
)
node._run_flux({"flux": 'from(bucket: "b")'})
assert seen["timeout"] == 2500
def test_a_falsy_return_is_a_mistake_not_silence():
"""Only None means "nothing to publish"."""
from fluksio.flow.nodes import Node
+32
View File
@@ -119,3 +119,35 @@ def test_the_configured_timeout_reaches_the_broker_client(monkeypatch):
asyncio.run(node._publish_once({"setpoint": 21.0}))
assert seen["timeout"] == 2.5
def test_the_configured_backlog_reaches_the_publish_queue(monkeypatch):
"""The depth is read when the queue is built, so it has to be per node."""
import aiomqtt
class FakeClient:
def __init__(self, **kwargs):
pass
async def __aenter__(self):
return self
async def __aexit__(self, *_):
return False
monkeypatch.setattr(aiomqtt, "Client", FakeClient)
node = MqttNode(
requires=[MessageSpec(name="setpoint", port="setpoint", dtype=DType.FLOAT)],
params={"topic": {"setpoint": "heating/setpoint"}, "publish_queue_size": 8},
)
node.assign_flow("heating", "out")
async def scenario() -> int:
await node.start_publisher()
assert node._publish_queue is not None
size = node._publish_queue.maxsize
await node.stop_publisher()
return size
assert asyncio.run(scenario()) == 8