Repository navigation
rutis v0.19.2
rutis 0.19.2
0.19.2 fixes bugs: places that gave wrong results, hung or made memory blow up. Plugin code and rutis.json stay as they are; the "Behaviour changes" section lists every difference you can see, and the three that affect code written today come first.
Read these three first
- TypeScript / Bun tests unload at the end of the test (#933, #971). The plugin
loadloaded is unloaded when its test ends and the fake services it gave are withdrawn, so a failed test no longer leaves its services to the next one (the next test used to getllm is already provided by rutis-test). Code that loads in one test and goes on using it in the next now getsPluginTestError: the plugin is unloadedin the second test: have each testloadits own. - A 30-second limit on the Python test tool's calls (#971). An asynchronous call of the service under test that does not return within 30 seconds fails with
PluginTestError: greeter.hello() did not return within 30 s; the test used to hang without a word. - A runtime path that is not there is an error (#935, #974). A
runtimes.node.runtimeorruntimes.bun.runtimenaming a path that does not exist used to switch quietly to a runtime found elsewhere; nowcheck,run,devandaddall sayruntimes.node.runtime names <path>, which does not exist(for a directory without package.json,…, which is no npm package (it has no package.json)). Aruntimes.py.projectthat does not exist used to be reported as the interpreter's error; now the message says the path does not exist.
Memory
- The memory peak when many instances close together (#977, #978). Each emit copied all the listeners of its event, and every queued event held its own copy; when the listeners grow with the number of instances, the peak grew with its square. Now emits without a filter share one listener list cached per event name, and nothing is allocated when there is no listener; an emit with a filter and
parallel/serial/waterfall/bailstill select each time. Measured on Dim (0.17.1, N=1000 sessions closed one after another): the closing peak goes from 3.43 GB to 444 MB (what the sessions use while running). Event order, filters,once/prependare unchanged.
Hosts
- A plugin evicted while loading returns to Pending when
build/validate/applyreturns an error (#968, #969). When a service a loading plugin uses is withdrawn, the kernel cancels that generation first; the plugin used to go toFailedafter that, was not retried when the same service came back, and onlyrestart()brought it back; now it returns toPendingand loads once more when the service comes back. A restart, update, dispose or shutdown while loading used to pass throughFailedonce (the final state was right); it no longer does. A panic after the cancellation still goes to the error sink once; a plugin cancelling its own token, and a genuine failure the driver did not cancel, are stillFailed. - An abandoned
reconcileno longer holds up later operations (#934, #972). After a host gave up areconcilewithtimeout(one row'sapplydoes not return), areloadof another row, anotherreconcileand the reload after a runtime restart used to never return; now they return as usual, and the stuck row is stillstarting.Loader::settled()still waits for every row.
rutis-host
- Under
check --strict, a misspelt row field and a row id used twice are errors (#974), exit code 1; without--strictthey are still warnings. A misspelt row field gets adid you mean. status/callsay where they looked when no host answers (#974):no rutis-host answers for <configuration> at <socket path> (XDG_RUNTIME_DIR=<value>), adding that for a host run as a service the command must run in its environment. The deployment section has a complete systemd unit and launchd plist.
rutis-host dev
- Python: a changed helper module of the plugin's package is now imported again, together with the other modules of the package (it used to print
reloadedand go on running the old code); modules outside the plugin's package still needdevrestarted. - Python: a
breakpoint()without--debugfails the call withRuntimeError: breakpoint() needs a terminal, and this Python runtime has none: run rutis-host dev --debug(it used to beBdbQuitorSystemExit: 1); under--debug, Ctrl-C after a breakpoint exits at once with exit code 0 (it used to wait the full 10 seconds and exit with 2). - Go: with several plugins in one binary, the project's own plugins are the rows
rutis.dev.jsonwrites (bannerrunning weather, llm); anameignored on a row of the same id gets a warning. - In a Python project with a
package.jsonat its root, it is a Node project only when the entry file thatpackage.jsonnames exists. - A row whose reload failed and whose previous version keeps running shows in
statusasrunning (the previous version: its last reload failed). - A row restarted by a change names its reason once:
caller: restarted (weather reloaded)(with several files changed together it used to berestarted (weather reloaded, weather restarted)).
Test tools
- TypeScript / Bun: while a test waits for the result of a function a plugin handed over,
node --testno longer takes the process for idle and cancels the test (#932, #967). The example of section 5 of Build a host open to plugins failed every time on Linux because of it.
Error messages and intermittent failures
- A failed wait for a runtime's greeting says why:
the runtime's channel failed: the read of its greeting was cancelled/… panicked: <message>. - When a runtime process exits, calls on its objects always say
runtime <name> exited(they sometimes saiddisconnected). - Two intermittently failing tests are fixed at their root (the fd handover in
test_command,waits.rsjudging complexity by elapsed time).
Documentation
What the 0.19.0 evaluation had to guess, or found different from what happens: the Go debugger version (dlv@v1.26.3, which installs with Go 1.24) and a dev-only fake service written in Go; the row id of a Python project in dev; a Rust plugin using another language's service by name, and how a plugin without configuration registers; how a host gets the state as text, and the type of processes(); rutis-host's row fields, its output formats, and which languages check argument types.
Behaviour changes
| Where | Before | Now |
|---|---|---|
| End of a TS / Bun test | the plugin load loaded stays until unload |
unloaded when the test ends |
| An asynchronous call in the Python test tool | hangs while it does not return | after 30 s, PluginTestError: … did not return within 30 s |
runtimes.node.runtime / runtimes.bun.runtime naming a path that is not there |
quietly uses a runtime found elsewhere | an error naming the path |
check --strict: a misspelt row field, a row id used twice |
warnings, exit code 0 | errors, exit code 1 |
status / call find no host |
no rutis-host runs … (status), no rutis-host run or dev is running for … (call) |
names the socket path and XDG_RUNTIME_DIR |
Evicted while loading, build / validate / apply returns an error |
Failed, not retried |
back to Pending, loaded again when the service returns |
| restart / update / dispose / shutdown while loading | passes through Failed once |
does not pass through Failed |
Operations after an abandoned reconcile |
never return | return as usual |
| Many instances closing together (listeners growing with instances) | the peak grows with the square of the instance count | linear in the instance count |
dev: a Python helper module changed |
prints reloaded, still the old code |
imported again |
dev: breakpoint() without --debug |
BdbQuit / SystemExit: 1 |
RuntimeError: … run rutis-host dev --debug |
dev --debug: Ctrl-C after a breakpoint |
waits 10 s, exit code 2 | exits at once, exit code 0 |
dev: a Go binary of several plugins |
the first in alphabetical order is the project's own, name dropped silently |
the rows rutis.dev.json writes are the project's own, a warning when name is dropped |
dev: a row restarted by a change |
the reason may repeat (weather reloaded, weather restarted) |
written once per row |
| A failed wait for a runtime's greeting | the runtime's channel failed |
followed by the cancellation or the panic |
| Calls on objects of a runtime that exited | sometimes disconnected |
always exited |
Compatibility
- The protocol is unchanged and 0.19.2 connects with 0.19.0 and 0.19.1 as usual. The formats of
rutis.jsonandrutis.dev.jsonare unchanged. - No public API is added or removed.
Packages
All of these are version 0.19.2: on crates.io rutis, rutis-macros, rutis-bridge, rutis-loader, rutis-types, rutis-host, rutis-sdk, rutis-dylib, rutis-dylib-meta, rutis-dylib-launcher; on npm @arcships/rutis, @arcships/rutis-runtime, @arcships/rutis-bun, @arcships/rutis-host and the five platform packages; on PyPI rutis, rutis-host; the Go module github.com/arcships/rutis/go/rutis (tag go/rutis/v0.19.2); the Swift package (v0.19.2); the rutis-host binaries on the GitHub release page. The Kotlin SDK, as in 0.19.0, is used from source at the tag v0.19.2.