Repository navigation
feat(lib): count publisher sends and errors, skip failing publishers - #712
arsenovicAtNominal wants to merge 2 commits into
Conversation
[High impact] The shared instrument publishing path changes across the library. The PR appears safe to merge, with non-blocking fixes recommended for fast-channel rates and buffer cleanup during concurrent stats reads. FindingsFix with agent prompt### Issue 1
instro/lib/stats.py:33
`arrivals` keeps only 512 updates, even when they all fall within the requested window. A channel receiving 1,000 single-sample updates per second therefore reports at most 102.4/s from `rate(5.0)`, rather than 1,000/s. This affects both `channel_stats` and the notebook card.
Keep counts for the full time window, using time buckets if memory must stay bounded. Add a test that exceeds 512 updates within that window.
### Issue 2
instro/lib/instrument.py:200-204
`_publisher_counter()` can recreate a buffer's counter after `stop()` removes it. For example, `publisher_stats` can copy `publishers`, pause while another thread finishes `stop()`, then resume and create a counter for the old buffer.
That counter keeps the closed buffer alive. Later stops only remove the new buffer's counter, so repeated restarts can accumulate unused buffers. Coordinate counter creation with publisher removal so an older reader cannot restore a removed entry.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.SummaryAdds publisher send/error counts, isolates publisher failures, and exposes channel counts and rates in Python and notebook cards.
|
|
Heads-up from #711 review changes (20797ec). Rebasing onto
|
|
One more from #711 (69b3f8c): the "Channel count" row moved from the |
Copy examples/notebooks/*.md into the docs, run them with myst-nb, and list them under Notebooks on the Examples tab. Add the notebook display demo (cards only; no hardware or Nominal credentials needed), the just notebook and test-notebooks recipes, and the docs for adding a notebook. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Instrument.publish() counts what each publisher does with every Measurement and Command. A publisher that raises is logged, counted and skipped, and the others still receive the data. Add Instrument.publisher_stats and channel_stats, a Publishers table and a channel rate and count on the notebook card, and move ChannelState and MonitorState into instro.lib.stats. The demo notebook gains a failing-publisher section and the stats calls. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
a2eac24 to
367d7ca
Compare
Summary
Second half of #709. Stacked on #713, which adds the notebook and the docs build that runs it, so review that first. Once #713 merges, change this PR's base to
main.Instrument.publish()counts what each publisher does with everyMeasurementandCommand.Instrument.publisher_stats: onePublisherStatssnapshot per publisher:sent,errors,last_error,last_sent_ns,last_error_ns.Instrument.channel_stats: the latest value, count and rate (state.rate(5.0)) of every channel, commands included. It doesn't needstart().ChannelStateandMonitorStatemove unchanged from the feat(monitor): live terminal monitor as a publisher target #510 branch (issue-510-monitor-publisher,instro/lib/consumers/monitor/server.py) intoinstro/lib/stats.py. Once this merges, feat(monitor): live terminal monitor as a publisher target #510 can import them from there instead of keeping its own copy.Demo notebook. #713 adds
examples/notebooks/notebook_display.md. This PR adds to it a "A failing publisher" section, which uses a deliberately failing publisher, and calls topublisher_statsandchannel_stats. It still needs no hardware or credentials.Type of change
feat)Verification
just check-pythonpasses, and so doesuv run pytest testsexcepttests/ethernetip, which I couldn't run because the locally built EtherNet/IP extension fails to load on my machine (unrelated to this change).just test-notebookspasses.just notebookservesnotebook_display.mdas a notebook.Instrument.publish()with an 8-channel measurement and 3 publishers went from 1.47 µs (plain loop) to 3.12 µs per call. That's small next to instrument I/O, so the stats are always on.Tests
tests/lib/test_publisher_stats.py:start()start()/stop()doesn't leak counters for dropped bufferstests/awg/test_awg_config_software.py:test_open_failure_in_a_publisher_drops_the_configured_channelasserted the old behaviour, where a publisher error abortsopen(). It is nowtest_a_failing_publisher_does_not_fail_open.test_open_failure_after_a_channel_succeeds_drops_the_configured_channels.Checklist
docs/library/publishers.md, the notebook-display guide, and theinstro.lib.statsentries indocs/ref/library/instrument.mdNotes for reviewers
feat!title.watch()view from feat(lib): notebook cards for instruments, Nominal connection options, and publisher stats #709.🤖 Generated with Claude Code