snakemake_bridge 0.2.0
snakemake_bridge: ^0.2.0 copied to clipboard
Embed a real-time Snakemake workflow monitor in a Dart desktop app: WebSocket server, typed event models, state reducer and process launcher.
Changelog #
0.2.0 #
Control over how the Snakemake process is launched. Additive: every new parameter defaults to the previous behaviour, and the protocol is unchanged (schema v1).
SnakemakeRunner.starttakesenvironmentandincludeParentEnvironment, passed through toProcess.start.Process.startincludes the parent environment by default, so the map holding the token was merged over the application's own environment rather than replacing it — and there was no way to ask for anything else. Snakemake inherited whatever the app was launched with, and so did every job it started. For an application that gives each tool its own conda environment that is a correctness problem: aPYTHONPATH, aLD_LIBRARY_PATHor an active conda env in the user's shell puts the wrong interpreter or shared library in front, and the failure is hard to trace back. PassingincludeParentEnvironment: falsenow builds the child's environment fromenvironmentalone. The token is merged last, so a staleSNAKEMAKE_LOGGER_DART_TOKENin the caller's map cannot shadow the run's own — for an exact-case key; Windows matches environment names case-insensitively. Note thatexecutableis resolved against thePATHof the map that was passed, not the parent's.SnakemakeRunner.starttakesworkdir, the directory the workflow writes into, defaulting toworkflowDiras before. The two were forced to be the same, soresults/and.snakemake/landed inside the workflow tree — which stops that tree from being read-only and shared between runs.workdiris passed as--directory, and the process still starts inworkflowDirso that Snakefile discovery keeps working for all four accepted layouts (Snakefile,snakefile,workflow/Snakefile,workflow/snakefile); passing--snakefileinstead would have meant guessing which one a given workflow uses. A consequence worth knowing: a relativeworkdirresolves againstworkflowDir, not against the application's working directory, so'runs/today'writes inside the workflow tree.extraArgsis documented as being appended last, so a caller can still override any argument the runner builds,--directoryincluded.- The pubspec now declares
platforms:as Linux, macOS and Windows. Nothing about the package had changed, but with the key absent pub.dev inferred support from thedart:iousage alone and advertised Android and iOS too — platforms where there is nosnakemakeprocess to launch in the first place. Every document already described the package as desktop-only; the metadata now says the same. - Documentation fix, no code change:
cancel()was described as cancelling the run, and it does not. Both signals reach the Snakemake process only, and Snakemake 9 does not pass them on to its jobs — onSIGTERMthe scheduler stops launching new jobs and waits for the running ones ("Will exit after finishing currently running jobs"), and theSIGKILLthat followskillAfterorphans every job still running, which then goes on writing into the working directory.SIGINTbehaves no better: the local executor'scancel()shuts down a thread pool whose threads are all blocked waiting on their job's process. The README now states this, and shows the process-group approach that does stop the jobs.README.md,ARCHITECTURE.md,SPEC.mdand the overview diagram carried the same wrong claim and were corrected.
0.1.1 #
Robustness and performance fixes; no protocol changes (schema v1).
SnakemakeRunner: output written by the process before the firststdout/stderrsubscriber is no longer lost. The streams were plainbroadcastcontrollers, which discard everything emitted while nobody is listening — and sincestartis asynchronous, the caller could never subscribe in time; for a process that wrote early, the initial output vanished entirely. It is now buffered (up to the newmaxBufferedLines) and delivered in order once a subscriber arrives.SnakemakeRunner: each stream now closes when it ends, rather than onexitCode— the process can exit before in-flight output is delivered. Decoding usesallowMalformed, so an invalid byte from a tool the workflow invokes no longer tears down the stream, and read errors are forwarded to the consumer instead of surfacing as an unhandled asynchronous error.WorkflowRunState: retention oflogLines/errorsno longer costs O(maxLogLines) per event. Trimming the front of aListon every line shifts the whole remainder and dominatedapplyon verbose runs; trimming now happens in blocks of the newtrimChunk, cutting the cost from ~21.6 µs to ~0.18 µs per log line. In exchange the limit became soft: the length may exceedmaxLogLinesby up totrimChunkbetween two trims.WorkflowEvent.fromJson: now honours what it already documented. The direct casts (as String?,as num,as Map?) threwTypeErroron any type mismatch; inside the server that silently dropped the whole event — the opposite of the intended forward compatibility. Each field now degrades on its own: a non-numeric entry injob_idsis skipped without discarding the batch, andfromJsonis safe to call directly, outside the server'stry.WorkflowRunState.byStatusnow returnsList<JobState>— a snapshot taken at call time — instead of the lazy view returned bywhere. That view rescanned on every read, which madeelementAt(i)quadratic: theitemCount+itemBuilderpattern of aListView.buildertook 8.4 s to walk 50k jobs, against ~1 ms now. Being a live view overjobs, it also changed size betweenitemCountanditemBuilder, and threwConcurrentModificationErrorwhen an event was applied mid-iteration. Not a breaking change:Listis a subtype ofIterable.WorkflowServerno longer lets apongadvance the deduplication cursor. A pong is answered out of band, ahead of whatever the plugin still has queued, so when it carried a real sequence number the cursor jumped past every event still in flight and those events were dropped for good — 36 of 50 in the measured case, triggered by nothing more than callingping(). Pongs are now delivered outside the ordered stream, likehello, which also protects against a plugin that still numbers them. SeeSPEC.md.- Example: warns on
stderrwhenSNAKEMAKE_LOGGER_DART_TOKENis unset, since the server then accepts any local connection.
0.1.0 #
- Initial release.
WorkflowServer: embedded WebSocket server (shelf), bound to127.0.0.1, token authentication, deduplication byseqand areplayrequest on every reconnection.workflow_events.dart: typed models of the Snakemake events (sealed classes; unknown types becomeUnknownEvent).WorkflowRunState: event reducer → queryable run state (jobs, progress, DAG, logs, errors).SnakemakeRunner: launches and owns thesnakemakeprocess.- Example
example/snakemake_bridge_example.dart: headless monitor for testing in the terminal.