Execution Architecture¶
Target Audience: Administrators, Developers Difficulty: Intermediate Prerequisites: Data Model, Job Lifecycle
Overview¶
MultiFlexi’s execution layer is made up of three independent daemons that run as systemd services. Each has a distinct responsibility:
┌─────────────────────┐ schedules ┌─────────────────────┐
│ multiflexi- │──────────────►│ Job queue │
│ scheduler │ │ (database) │
└─────────────────────┘ └──────────┬──────────┘
│ picks up
┌─────────────────────┐ triggers ┌──────────▼──────────┐
│ multiflexi- │──────────────►│ multiflexi- │
│ event-processor │ │ executor │
└─────────────────────┘ └─────────────────────┘
Scheduler (multiflexi-scheduler) — scans RunTemplates and enqueues jobs at the configured interval
Event Processor (multiflexi-eventor) — watches for external events and triggers jobs in response
Executor (multiflexi-executor) — picks jobs from the queue, resolves their environment, and runs them
The three daemons are fully decoupled and communicate only through the shared database. All three can be scaled horizontally if needed.
The Scheduler Daemon¶
The scheduler runs as multiflexi-scheduler.service. It wakes up periodically, iterates over all enabled RunTemplates, and creates a Job record for any RunTemplate whose next scheduled run time has passed.
Scheduling intervals available in RunTemplates:
Manually (on-demand only)
Hourly (at the start of each hour)
Daily (once per day)
Weekly (once per week)
Monthly (once per month)
Yearly (once per year)
The scheduler writes the next scheduled time back to the RunTemplate after enqueuing, preventing duplicate enqueuing.
systemd service unit:
[Unit]
Description=Run MultiFlexi scheduled jobs
After=multi-user.target
[Service]
User=multiflexi
Group=multiflexi
EnvironmentFile=/etc/multiflexi/multiflexi.env
ExecStart=/usr/bin/php /usr/lib/multiflexi-scheduler/daemon.php
LimitNOFILE=8192:16384
Type=simple
Restart=always
RestartSec=10
The Event Processor Daemon¶
The event processor runs as multiflexi-eventor.service. It monitors configured event sources and fires jobs in response to external triggers rather than time-based schedules.
Typical use cases:
Trigger a job when a new file appears in a directory
React to a webhook notification
Start processing when a message arrives on a queue
systemd service unit:
[Unit]
Description=MultiFlexi Event Processor - event-driven job triggering
After=multi-user.target
[Service]
User=multiflexi
Group=multiflexi
EnvironmentFile=/etc/multiflexi/multiflexi.env
ExecStart=/usr/bin/php /usr/lib/multiflexi-eventor/daemon.php
LimitNOFILE=8192:16384
Type=simple
MemoryMax=1G
Environment=MULTIFLEXI_MEMORY_LIMIT_MB=900
Restart=always
RestartSec=10
The Executor Daemon¶
The executor runs as multiflexi-executor.service. It is the core of job execution. Its main loop:
Queries the database for the next pending
JobrecordResolves the full environment for that job (config fields + assigned credentials)
Selects and invokes the configured executor module (see below)
Captures stdout, stderr, and any output files
Stores all output as artifacts in the
artifactstableRecords the exit code and updates the job status (success / failed)
Fires any configured post-job actions
The executor has a configurable memory ceiling (default: 2 GB) and restarts automatically if it crashes or exceeds the memory limit.
systemd service unit:
[Unit]
Description=Run MultiFlexi scheduled jobs
After=multi-user.target
[Service]
User=multiflexi
Group=multiflexi
EnvironmentFile=/etc/multiflexi/multiflexi.env
ExecStart=/usr/bin/php /usr/share/multiflexi-executor/daemon.php
LimitNOFILE=8192:16384
Type=simple
MemoryMax=2G
Environment=MULTIFLEXI_MEMORY_LIMIT_MB=1800
Restart=always
RestartSec=10
Executor Modules¶
Each RunTemplate selects an executor module that determines where the job process runs.
Module |
Description |
Requirement |
|---|---|---|
|
Runs directly on the host as the |
Default; no extras |
|
Runs inside a Docker container |
Docker installed |
|
Runs inside a Podman container (rootless) |
Podman installed |
|
Runs as a one-shot Kubernetes pod via kubectl+Helm |
kubectl + helm |
|
Runs in Azure Container Instances (experimental) |
Azure credentials |
The Native executor is the default and simplest option. The Docker and Podman executors provide process isolation. Kubernetes is suitable for cloud-native deployments.
See Executors for complete configuration details for each module.
Environment Variable Resolution¶
Before any job is launched, the executor builds the complete environment by merging (in order of increasing precedence):
System-level defaults from
/etc/multiflexi/multiflexi.envCompany-level environment variables (
company_envtable)RunTemplate configuration field values
Assigned credential field values
This means credential values can override RunTemplate values, which can override company defaults. The final merged set of variables is passed to the child process.
Artifact Preservation¶
Every job — regardless of which post-job actions are enabled — automatically preserves its outputs in the artifacts database table:
stdout.txt — standard output of the job process
stderr.txt — standard error of the job process
result files — any output files produced by the application (MIME type auto-detected)
Artifacts are accessible from the Job detail page in the web UI, or via the REST API. They are cascade-deleted when the Job record is deleted.
Post-Job Actions¶
After a job completes, the executor can fire a configured set of Actions. Actions are evaluated against the job’s exit code and can perform notifications, trigger further jobs, or integrate with external systems.
See Actions for the complete list of available actions.
See Also¶
Job Lifecycle — Detailed state transitions of a Job
Executors — Executor module configuration
Actions — Post-job actions
Systemd Services — Managing the daemons