tomato.daemon: Functions and modules comprising the tomato daemon
Code author: Peter Kraus
- tomato.daemon.setup_logging(daemon: Daemon)
Helper function to set up logging (folder, filename, verbosity, format) based on the passed daemon state.
- tomato.daemon.tomato_daemon()
The function called when
tomato-daemonis executed.Manages the state of the tomato daemon, spawning manager threads for jobs (
job), drivers (driver), and pipelines (pip). Parses the configuration in the settings file and devices file.
Submodules
tomato.daemon.cmd: command parsing for tomato daemon
Code author: Peter Kraus
All functions in this module expect a dict containing the command specification and a Daemon object as arguments. The Daemon object may be altered by the command.
All functions in this module return a Reply.
- tomato.daemon.cmd.status(msg: dict, daemon: Daemon) Reply
Return daemon status, containing the current tomato configuration.
- tomato.daemon.cmd.reload(msg: dict, daemon: Daemon) Reply
Set-up or reload the tomato daemon using its configuration files.
Note
When reloading settings, tomato checks whether any running jobs use resources (i.e. drivers, pipelines, components) that would be removed if the new configuration were to be applied. If this is the case, the configuration will not be updated.
tomato.daemon.crates: functions for creating RO-crates
Code author: Peter Kraus
- tomato.daemon.crates.RepositoryObject(crate: ROCrate, identifier: str | None = None, properties: dict | None = None) ContextEntity
- tomato.daemon.crates.Profile(crate: ROCrate, identifier: str = 'https://github.com/MADICES/MADICES-2025/discussions/25', properties: dict | None = None) ContextEntity
- tomato.daemon.crates.to_rocrate(datapath: str, userid: str, sampleid: str, make_child: bool = True) ROCrate | None
- tomato.daemon.db.connect_db(dbpath: str | Path)
- tomato.daemon.db.setup_db(dbpath: str | Path) None
tomato.daemon.driver: the driver manager of tomato daemon
Code author: Peter Kraus
- tomato.daemon.driver.tomato_driver_bootstrap(req: Socket, logger: Logger, interface: ModelInterface | ModelInterface, driver: str)
Function that attempts to register all configured components for this driver.
This helper function is executed when the
registercommand is set to the driver process. The daemon is first polled for up-to-date configuration, and then each of the returned components is registered, if necessary, usingcmp_register()of the driver interface.In case the registration fails, a limited number of retries (as specified by the
MAX_REGISTER_RETRIESconstant) can be attempted on subsequent runs of this function.
- tomato.daemon.driver.perform_idle_measurements(interface: ModelInterface | ModelInterface, t_last: float | None) float | None
Function running idle measurements on the driver.
This function periodically runs the
cmp_measure()on each component on the driver. The interval is determined from driver configuration using the"idle_measurement_interval"setting, driver defaults using theinterface.idle_measurement_intervalobject, or tomato default (IDLE_MEASUREMENT_INTERVAL).Note
How idle measurements are handled is up to the individual driver. By default, the
cmp_measure()function will not submit new measurements when a task or a measurement is already running.
- tomato.daemon.driver.stop_tomato_driver(port: int) Reply
The default mechanism for stopping tomato drivers.
This function is used by the tomato driver manager to gracefully stop the driver, if an existing driver port is known.
- tomato.daemon.driver.kill_tomato_driver(pid: int)
The backup mechanism for stoping tomato drivers.
This function is useful if the driver port is unknown or not responsive.
Wrapper around
psutil.terminate(). Here we kill the (grand)children of the process with the name of tomato-job, i.e. the individual task functions. This allows the tomato-job process to exit gracefully once the task functions join.Note
On Windows, the tomato-job.exe process has two children: a python.exe process which is the actual process running the job, and conhost.exe process, which we want to avoid killing.
- tomato.daemon.driver.tomato_driver() None
The function called when tomato-driver is executed.
This function is responsible for managing all activities involving devices of a single driver type.
First, the list of devices (and their channel/address) for the specified driver is fetched from the tomato-daemon. Then, a new instance of the specified driver is spawned, populating its device map using the above list. The state of the driver is stored .
Afterwards, the main loop handles all requests related to each of the devices managed by this driver process, including job commands. Finally, if the driver is instructed to stop, it attempts to perform a teardown before exiting.
- tomato.daemon.driver.manager(timeout: int = 1000)
The driver manager thread of tomato-daemon.
This manager ensures individual driver processes are (re-)spawned and instructed to quit as necessary. The drivers are periodically checked using the
HEARTBEATconstant as the interval. All changes are stored in the drivers table.
tomato.daemon.drvdb: the sqlite database for drivers in tomato
Code author: Peter Kraus
tomato.daemon.io: functions for storing job data
Code author: Peter Kraus
- tomato.daemon.io.merge_netcdfs(job: Job, snapshot=False) str
Merges all of the individual pickled
Datasetfiles from each component found injob.jobpathinto a singleDataTree, which is then stored in the NetCDF file. The role of each component is used as the group label.
- tomato.daemon.io.data_to_pickle(ds: Dataset, path: Path, role: str)
Dumps the data provided as
Datasetusingpickle. Concatenates the new data with any existing data stored in the existing.pklfile.
tomato.daemon.job: the job manager of tomato daemon
Code author: Peter Kraus
- tomato.daemon.job.method_validate(method: Sequence[Task], pip: Pipeline, daemon: Daemon) bool
Function for validating
Taskparameters against components.This function finds a component on the pipeline that matches the role of each
Task, and passes eachTaskto thetask_validate()function of that component.Note
This function should be used to theck the method only after a matching pipeline has been identified, e.g. using
find_matching_pipelines().
- tomato.daemon.job.find_matching_pipelines(daemon: Daemon, method: Sequence[Task]) list[str]
Function for finding the names of pipelines that match the provided method.
The matching is performed using the required roles of the method as well as using the required capabilities of the method. The role-matching can be checked statically against the
daemon.devicefile; the latter is checked dynamically by polling each component for its capabilities usingcmp_capabilities().
- tomato.daemon.job.kill_tomato_job(process: Process)
Wrapper around
psutil.terminate().Here we kill the (grand)children of the process with the name of tomato-job, i.e. the individual task functions. This allows the tomato-job process to exit gracefully once the task functions join.
Note
On Windows, the tomato-job.exe process has two children: a python.exe process, which is the actual process running the job, and conhost.exe process, which we want to avoid killing.
- tomato.daemon.job.manage_running(daemon: Daemon)
Function that manages jobs within the tomato job manager.
The function only affects jobs marked as running, i.e. with a set
pid. Jobs scheduled for killing (i.e.status == "rd") are terminated. Jobs that are supposed to be running but have crashed are given appropriate status ("ce").Note
Successful job completions are not processed here, but within the job process.
- tomato.daemon.job.check_queued(daemon: Daemon) dict[int, list[str]]
Function to check whether the queued jobs can be submitted onto any configured pipeline.
Returns a
dictcontaining the jobids as keys and lists of matchedPipelinesas values.
- tomato.daemon.job.action_queued(daemon: Daemon, matched: dict[int, list[str]])
Function that assigns jobs if the pipeline is ready and contains the requested sample.
Warning
No validation except checking the sample name and readiness is performed. A matching and validated pipeline has to be previously identified, using e.g. the
check_queued()function.Note
The tomato-job process is launched from this function.
- tomato.daemon.job.manager(timeout: int = 500)
The job manager thread of tomato-daemon.
This manager ensures the job queue is iterated over and jobs are submitted to pipelines.
Note
Note that we poll the tomato-daemon for configuration only once per iteration of the main loop.
- tomato.daemon.job.tomato_job() None
The function called when tomato-job is executed.
This function is responsible for managing all activities of a single job, including updating the queue table with the job pid, spawning of sub-processes to run tasks on each component of the pipeline, merging data at the end of the job, and updating the state of the pipeline once the job is successfully finished.
- tomato.daemon.job.job_thread(role: str, tasks: list[Task], component: Component, device: Device, dport: int, dsettings: dict, jobpath: Path, logpath: Path)
A subthread of tomato-job, responsible for tasks on one component of a pipeline.
For each
Task, this thread starts the task at an appropriate moment, then monitors the component status and polls periodically for data, and moves on to the next task as instructed in the task list.Note
The data from all tasks for that component is stored using the
tomato.daemon.io.data_to_pickle()function.
- tomato.daemon.job.job_main_loop(port: int, job: Job, pipname: str, logpath: Path) int | None
The main loop function of tomato-job, split for better readability.
tomato.daemon.jobdb: the sqlite database for jobs in tomato
Code author: Peter Kraus
tomato.daemon.lpp: a lazy pirate pattern implementation
Code author: Peter Kraus
- tomato.daemon.lpp.comm(req: Socket, data: Any, endpoint: str, retries: int = 3, timeout: int = 1000, sender: str | None = None) tuple[Reply, Socket]
Communication function based on the lazy pirate pattern.
This is a more robust version of the classic request–reply pattern, as the reply has a timeout (by default set to the
REQ_TIMEOUTconstant). The request–reply pattern is retried several times (by defaultREQ_RETRIEStimes), closing the connection between each retry.
tomato.daemon.pip: the pipeline manager of tomato daemon
Code author: Peter Kraus
- tomato.daemon.pip.manager(timeout: int = 500)
The pipeline manager thread of tomato-daemon.
This manager ensures the job queue is iterated over and pipelines are managed/reset. Note that we poll the tomato-daemon for status only once per iteration of the main loop.
tomato.daemon.pipdb: the sqlite database for pipelines in tomato
Code author: Peter Kraus