← CLI

CLI FEATURE

Workers & Scheduling

Semitexa is not only request-response code. The CLI also owns the long-running workers and operator interventions that keep the platform moving.

Feature Guide

A quick orientation block that answers the essential questions: what this feature does, how it works, why it matters, and the key concepts behind it.

What this does

Semitexa CLI also owns the long-running side of the platform: queues, schedules, webhook delivery, mail workers, and tenant-context execution.

How it works

Dedicated commands expose each stage separately: inspect schedules, plan due runs, start workers, inspect webhook inbox/outbox state, replay deliveries, and run commands in tenant scope.

Why it matters

This makes background systems operable. Operators can inspect, intervene, and replay explicitly instead of treating async infrastructure as invisible magic behind the web server.

Key concepts

queue:work
Runs the async events worker for queued handlers.
scheduler:plan
Materializes due schedule occurrences into concrete run rows before workers execute them.
tenant:run
Executes any command inside a specific tenant context.

Operator Runtime

Long-running platform work is part of the same command surface

Async queues, scheduler pools, outbound webhooks, mail delivery, and tenant-scoped execution all surface through explicit commands. That makes the runtime operable without custom one-off scripts.

Dedicated workers. queue:work, webhook:work, and mail:work turn background processing into explicit operator processes rather than hidden side-effects.

Planner plus executor. The scheduler surface is separated into list, plan, run-now, and work so teams can inspect and intervene before blindly starting daemons.

Context-aware execution. tenant:run lets operators execute commands inside a concrete tenant context instead of manually injecting environment assumptions.

Command Purpose Why it matters
bin/semitexa queue:work nats async Run the async events worker against a chosen transport and queue. Keeps event-driven background work explicit and separately operable.
bin/semitexa scheduler:list && bin/semitexa scheduler:plan Inspect configured schedules, then materialize due runs. Good operational sequence before starting or debugging the scheduler worker.
bin/semitexa webhook:show outbox --status=pending && bin/semitexa webhook:work Inspect webhook backlog, then run delivery worker. Makes outbound integration behavior reviewable rather than opaque.
bin/semitexa tenant:run acme cache:clear --twig Run a command inside a tenant context. Critical when the platform behavior depends on tenant-aware configuration or data isolation.

Bring up the scheduler loop deliberately

bin/semitexa scheduler:list
bin/semitexa scheduler:plan
bin/semitexa scheduler:work default

Inspect and replay webhook traffic

bin/semitexa webhook:show inbox --limit=10
bin/semitexa webhook:replay:inbound <delivery-uuid>

Operate background work in one tenant

bin/semitexa tenant:run acme queue:work
bin/semitexa tenant:run acme cache:clear --twig
queue:work scheduler:list scheduler:plan scheduler:work webhook:work tenant:run

Verified against Semitexa Ultimate 2026.09.19.1020

Workers & Scheduling

Semitexa is not only request-response code. The CLI also owns the long-running workers and operator interventions that keep the platform moving.

How it works

queue:work, webhook:work, and mail:work are separate explicit processes rather than hidden side-effects of the web runtime. The scheduler surface is split into scheduler:list (inspect), scheduler:plan (materialize), and scheduler:work (run the loop) so teams can inspect state before pushing harder. tenant:run executes any command inside a concrete tenant context, including queue and cache operations.

Why this matters

Operability matters as much as functionality. Separate inspect, plan, execute, and replay actions mean the platform can be observed and intervened on deliberately instead of forcing operators to restart processes and hope for the best.

© Edsger W. Dijkstra: "Simplicity is prerequisite for reliability."

queue:work Command Implementation slice
<?phpdeclare(strict_types=1);namespace Semitexa\Core\Application\Console\Command;use Semitexa\Core\Attribute\AsCommand;use Symfony\Component\Console\Command\Command;use Symfony\Component\Console\Input\InputArgument;use Symfony\Component\Console\Input\InputInterface;use Symfony\Component\Console\Input\InputOption;use Symfony\Component\Console\Output\OutputInterface;use Symfony\Component\Console\Style\SymfonyStyle;#[AsCommand(name: 'queue:work', description: 'Run async events worker (processes handlers enqueued with execution: async)')]class QueueWorkCommand extends Command{    protected function configure(): void    {        $this->setName('queue:work')            ->setDescription('Run async events worker (processes handlers enqueued with execution: async)')            ->addArgument('transport', InputArgument::OPTIONAL, 'Transport: nats or in-memory (default from EVENTS_ASYNC)', null)            ->addArgument('queue', InputArgument::OPTIONAL, 'Queue name (default from EVENTS_QUEUE_DEFAULT)', null)            ->addOption('timeout', 't', InputOption::VALUE_OPTIONAL, 'Worker timeout in seconds', null);    }    protected function execute(InputInterface $input, OutputInterface $output): int    {        $io = new SymfonyStyle($input, $output);        $transport = $input->getArgument('transport');        $queue = $input->getArgument('queue');        $io->title('Events worker (queue)');        try {            $worker = new \Semitexa\Core\Queue\QueueWorker();            $worker->setOutput($output);            $worker->run($transport, $queue);        } catch (\Throwable $e) {            $io->error('Worker failed: ' . $e->getMessage());            return Command::FAILURE;        }        return Command::SUCCESS;    }}

Ops Pattern

Healthy command topology for background systems

The value here is operability: separate inspect, plan, execute, and replay actions so the platform can be observed before it is pushed harder.

Separate “show/list” commands from “work/replay/run-now” commands so operators can inspect state before mutating it.

Treat workers as first-class processes with their own commands, not as accidental sidecars hidden behind the web runtime.

Use tenant:run when operational intent is tenant-specific instead of hoping ambient context is correct.

Scheduler surfaces are stronger when planning and execution remain explicit and individually observable.

How it works

Dedicated commands expose each stage separately: inspect schedules, plan due runs, start workers, inspect webhook inbox/outbox state, replay deliveries, and run commands in tenant scope.

Why it matters

This makes background systems operable. Operators can inspect, intervene, and replay explicitly instead of treating async infrastructure as invisible magic behind the web server.

Key concepts

queue:work
Runs the async events worker for queued handlers.
scheduler:plan
Materializes due schedule occurrences into concrete run rows before workers execute them.
tenant:run
Executes any command inside a specific tenant context.

Support Semitexa
Built for developers who prefer control over magic. Your support helps keep it fast, open, and evolving.

Donate via PayPal