7.1 KiB
Design and Development Guide
A schema is generally more easy to understand than a long speech. The following drawing describe the role of the different bricks involved in chore/chored system.
[client]
________/
| |
| chore |
|________|
||
|| unix socket
||
_||_ [children] [children]
__\__/__ /______________ /__________
| | | | | |
| chored |---[pipe]-->| chored_worker |---[stdin]-->| job |
| |<--[pipe]---| |<--[stdout]--| (command) |
|________| |_______________|<--[stderr]--|___________|
/ ||
[daemon] _||_
__\ /_
| \
| |
| logs |
| |
|________|
When chored is started, it will initialize its environment by
creating required directories and files.
When a new job is started, chored spawns a new chored_worker for
every new job. Two pipes are opened between chored and
chored_worker.
chored_worker is in charge of the job to execute and can control
STDIN/STDOUT/STDERR (STDERR should always be appended to logs).
When the job dies, chored_worker sends the return code to chored,
and closes all its file descriptor.
Constraints
-
small. This application MUST BE optimized for size, and SHOULD USE only required libraries.
-
portable. This application SHOULD RUN on every Unix/Posix systems. If possible it COULD BE designed like an embedded app.
-
light. This application should use a deterministic amount of memory. To accomplish that, strict limits must be imposed during compile time. For example, a relase can be compiled to only support 1 job.
-
stack first. This is a bonus constraint. If light enough, the release SHOULD USE the stack instead of the heap.
-
secure. This application MUST FOLLOW OpenBSD design principle and all best practice. If possible, when compiled for another operating system, it SHOULD USE local framework to make the application safer to use.
-
documented. All part of the code SHOULD HAVE its documentation. The whole applicatoin MUST BE documented and offers man pages.
Libraries
Libevent
Data structures
Protocols
States
Events
-
chore to chored via (unix sock)
- a new connection is created
- connection is closed
-
chored to chored workers (pipe)
- chored send a command to a worker
- chored fetch process information
- chored collect states
- chored collect statistics
-
chored worker to chored (pipe)
- a worker sends its state
- a worker sends its statistics
-
chored worker to job (socket or pipe?)
- sends stdin
- receives stdout
- receives stderr
- redirects to logs
- sends signals
- receive signals
chored state
chored_worker state
Procedures
chored
-
chored_init -
create environment
-
initialize data structures
-
chored_loop -
check if
worker[i]is here -
send ping to
worker[i] -
receive ping from
worker[i] -
send command to
worker[i](if defined) -
receive command result from
worker[i] -
chored_terminate -
send terminate command to all workers
-
wait until all workers are being stopped
-
close all file descriptors
-
exit with specific code
File management
| type | path | note |
|---|---|---|
| directory | ${HOME}/.config/chore |
main directory |
| directory | ${HOME}/.config/chore/run |
chored sessions directory |
| file | ${HOME}/.config/chore/run/${session}.pid |
chored session pid file |
| unix sock | ${HOME}/.config/chore/run/${session}.sock |
chored session unix sock file |
| file | ${HOME}/.config/chore/cache/${session}/jobs/${job_name}-${date}.pid |
job pid |
| file | ${HOME}/.config/chore/cache/${session}/jobs/${job_name}-${date}.debug |
job debug (data structure dump) |
| fifo | ${HOME}/.config/chore/cache/${session}/jobs/${job_name}-${date}.stdin |
job stdin fifo (disabled by default) |
| file | ${HOME}/.config/chore/cache/${session}/jobs/${job_name}-${date}.stdout |
job stdout log file |
| file | ${HOME}/.config/chore/cache/${session}/jobs/${job_name}-${date}.stderr |
job stderr log file |
| file | ${HOME}/.config/chore/cache/${session}/jobs/${job_name}-${date}.stats |
stats file (dynamically overwritten) |
Memory view
Features
Debug mode
When in debug mode, chored and chored workers print verbose
information during the different tasks they have to apply.
React mode
Pin mode
A job can be pinned, that's mean its current state (even if stopped) will never be removed. This job can be restarted on demand, its state and stats will be updated accordingly. When unpinned, the job state will be cleaned if someone check its jobs.
Operating Systems Specificities
OpenBSD
Linux
FreeBSD
NetBSD
DragonFlyBSD
MacOS
Minix
FAQ
What is the versionning format used?
Major.Minor.Bugfix
What was inspired from?
Mainly OpenBSD cron(8) daemon and by
extension at(1) but also
Hashicorp Nomad.
Why libevent?
To deal with many file descriptors, one can use
select(2) or
poll(2), but the way to deal with
that can be quite complex, and libevent was designed for this kind
of issue
Why process first?
Threads are complex to manage, can lead to many problems no one wants to deal with. Processes are not easy to manage at first, but they are isolated between them. Furthermore, the current application does not need incredible performance, the goal is to follow and processes locally.
Why stack first?
Well, for the first part of the project, the main goal is to create a
job scheduler (that's what it is, spawning a command, waiting for its
result and so on). No thread, only new processes with
fork(2) and
execve(2). A big part of the
required information can be put on the stack, it looks even more
possible if hard limits are set during compile time.
Don't forget, this project MUST BE minimalist.
Ideas
- configuration file
- chored state file (configuration?)
- pre-command
- post-command
- react on started job(s)
- react on stopped job(s)
- react on killed job(s)
- logs rotation
- alert(s)
- capabilities
- (linux) namespace
- (linux) cgroup
- (freebsd) jails
- communication between workers
- using zeromq?
- using binary format or a serializer between chored and its workers
- cbor? see tinycbor
- etf? see erlang term format