The Job Pipeline

How a user action becomes a durable background job that is consumed, executed, and fans out into sub-jobs.

Overview

Almost nothing happens synchronously in Pomavo beyond the database write that records your action. Search indexing, history, notifications, automations, thumbnails, attachment tracking, all of it runs afterward in the Worker, driven by a durable message log. This keeps the API fast and makes side effects reliable and retryable.

From Action to Job

The API records an event

When you create a ticket, change a field, add a comment, or start a sprint, the Web API persists the change and emits a typed event describing what happened.

The event becomes a durable job

The event is mapped to a job type and written as a job record, then published to the messaging log. The job record is the durable, inspectable unit of work.

The Worker consumes it

A feeder consumes from the messaging log and partitions work onto an internal queue, so independent jobs proceed concurrently while related work stays ordered.

A handler executes it

The orchestrator dequeues the job, resolves the correct handler for its type, and runs it, recording a job run with status and a full log.

Handlers fan out into sub-jobs

A single user action typically spawns several sub-jobs - index the ticket, record history, push to inboxes, and evaluate automations - each tracked independently.

Messaging and Storage

  • Messaging is a durable, partitioned log. Jobs are published to it and consumed by Worker instances in a shared consumer group, so work is balanced and survives restarts.
  • Job records and run logs live in a document store, which suits their flexible shape, such as arbitrary payloads, embedded run history, and per-run log lines, and their lifecycle, where short-lived event jobs expire automatically and scheduled jobs persist until they finish.

A job run moves through a small set of states - created, running, then succeeded, errored, requeued, or terminated - recorded atomically so the same job is never double-processed.

Trigger Types

Jobs come in three flavors:

TriggerRuns
QueueImmediately, in response to an event on the messaging log
CronOn a recurring schedule
DependentAfter another job completes

Sub-Jobs

The fan-out step is what makes the system composable. Common sub-jobs include:

  • Search index: keep Elasticsearch in sync with the ticket
  • History record: append to the ticket's activity history
  • Inbox push: deliver notifications to followers, assignees, and mentions
  • Thumbnail generation: render previews for image attachments
  • Attachment tracking: maintain references so unused files can be cleaned up
  • Automation executor: evaluate matching automation rules for the event
  • Scheduler fired: resume a deferred automation branch when its time arrives

Automations on the Pipeline

Automations ride this same pipeline. When an event matches an enabled rule, an automation executor sub-job runs the engine against the event. Before running, it checks the organization's quota: each evaluation counts toward the automation_runs metric over a rolling window, and runs are skipped and recorded as skipped once the limit is reached.

Scheduler nodes use a dedicated scheduler-fired job. A polling service finds scheduled instances whose fire time has arrived, publishes a scheduler-fired job, and the handler resumes the automation from its snapshot, restoring the exact upstream values captured at fork time.

Inspecting Jobs

Every job, run, and log line is inspectable from the Admin Dashboard. Because each side effect is its own tracked job, you can pinpoint exactly which step of a complex action succeeded, failed, or retried.