Background jobs, domain events, and side effects

**When to use:** Queues and workers, domain event publishers, async notifications or projections, or **not** doing that work inside HTTP handlers.

3,940 stars

Best use case

Background jobs, domain events, and side effects is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

**When to use:** Queues and workers, domain event publishers, async notifications or projections, or **not** doing that work inside HTTP handlers.

Teams using Background jobs, domain events, and side effects should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/async-jobs-and-events/SKILL.md --create-dirs "https://raw.githubusercontent.com/latitude-dev/latitude-llm/main/.agents/skills/async-jobs-and-events/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/async-jobs-and-events/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How Background jobs, domain events, and side effects Compares

Feature / AgentBackground jobs, domain events, and side effectsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

**When to use:** Queues and workers, domain event publishers, async notifications or projections, or **not** doing that work inside HTTP handlers.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Background jobs, domain events, and side effects

**When to use:** Queues and workers, domain event publishers, async notifications or projections, or **not** doing that work inside HTTP handlers.

## Side effects and eventing

- Domain code emits **domain events** through **domain-level publisher** abstractions (ports), not ad-hoc calls from use-cases to email/HTTP/Slack.
- **Workers** handle notifications, integrations, projections, and other I/O **asynchronously**.
- **Do not** orchestrate side effects (fan-out integrations, “fire and forget” HTTP, etc.) inside HTTP handlers — enqueue / publish and return.

## Async and background tasks

- Put **IDs** or opaque storage keys in job payloads — not full mutable entities.
- **Re-fetch** authoritative state inside the worker before acting.
- Make **stale or deleted** entities an explicit outcome (skip, dead-letter, or record failure) instead of assuming rows still exist.
- For **transactional domain events**, write through the **`OutboxWriter`** port in `@domain/events` (for example `createOutboxWriter` from `@platform/db-postgres`) instead of inserting outbox rows directly.
- For **high-volume or otherwise non-transactional producers** whose upstream write is already durable, publish directly through **`createEventsPublisher(queuePublisher)`** into `domain-events` instead of persisting an outbox row only to forward it.
- Domain-event consumers should act as **dispatchers**: publish downstream topic tasks or start workflows, but do not run synchronous business logic inline inside the event handler.
- Extend the repo’s existing async rails instead of inventing new ones: BullMQ-backed queue workers live in `apps/workers`, and durable multi-step workflows live in the Temporal-backed `apps/workflows` app.
- Queue topics may own several related **lower-kebab-case** task names; one worker module owns the topic and dispatches by task name.
- Queue publication should expose logical **dedupe/debounce** keyed by the relevant entity identity when the transport supports it.
- Use **queue topics** for single-step tasks and the **workflow abstraction** for long-running or multi-step orchestration.
- For reliability async contracts, include both `organizationId` and `projectId` in domain-event payloads, topic/task payloads, and workflow inputs by default. Exceptions: `MagicLinkEmailRequested`, `InvitationEmailRequested`, `UserDeletionRequested`, the `domain-events` topic payload, the `magic-link-email` topic payload, the `invitation-email` topic payload, and the `user-deletion` topic payload.
- When BullMQ delay is the chosen debounce mechanism, key the delayed job by the logical entity identity so newer writes replace or reschedule the pending job.
- When a delayed queue topic semantically marks a lifecycle edge, let the delayed task publish a domain event through the appropriate rail after the delay elapses: use `OutboxWriter` for transactional boundaries and direct `EventsPublisher` publication for non-transactional or high-volume worker flows. Downstream side effects should run from the domain-event consumers rather than inline in the delayed task.

## New infrastructure dependencies

When adding a new external system the product talks to:

1. Add a concrete provider package in `packages/platform/*-<provider>`.
2. **Wire** it in the app composition root from **environment-driven** config.
3. Change **domain** only if **business rules** change — not for every new adapter.

For env var naming when wiring config, see [env-configuration](../env-configuration/SKILL.md). For layer rules, see [architecture-boundaries](../architecture-boundaries/SKILL.md).

Related Skills

web-frontend

3940
from latitude-dev/latitude-llm

apps/web UI — routes, @repo/ui, TanStack Start server functions and collections, forms, Tailwind layout rules, design-system updates, and useEffect / useMountEffect policy.

toolchain-commands

3940
from latitude-dev/latitude-llm

Installing dependencies, running dev/build/test/lint, filtering packages, single-test runs, git hooks, preparing a clone (.env.development / .env.test), or Docker-backed local services and dev servers.

testing

3940
from latitude-dev/latitude-llm

Writing or debugging tests, choosing unit vs integration style, Postgres/ClickHouse tests, regenerating ClickHouse test schema, or exporting test helpers from packages without pulling test code into production bundles.

gh-issue

3940
from latitude-dev/latitude-llm

Create clear, actionable GitHub issues for bugs, features, and improvements. Issues are primarily consumed by LLMs, so optimize for agent readability and actionability.

env-configuration

3940
from latitude-dev/latitude-llm

Adding or reading env vars, updating .env.example, or validating config at startup with parseEnv / parseEnvOptional.

effect-and-errors

3940
from latitude-dev/latitude-llm

Composing Effect programs, domain errors, HttpError, repository error types, or error propagation at HTTP boundaries.

database-postgres

3940
from latitude-dev/latitude-llm

Drizzle schema, repositories, RLS, SqlClient wiring, Postgres migrations, psql / reset, or platform mappers (toDomain* / toInsertRow).

database-clickhouse-weaviate

3940
from latitude-dev/latitude-llm

ClickHouse queries, Goose migrations, chdb test schema, Weaviate collections/migrations, or telemetry storage paths.

code-style

3940
from latitude-dev/latitude-llm

Biome formatting, import style, strict TypeScript, naming (including React file names), or generated files.

authentication

3940
from latitude-dev/latitude-llm

Sessions, sign-in/sign-up flows, OAuth, magic links, or organization context on the session.

Web app frontend (`apps/web`)

3940
from latitude-dev/latitude-llm

**When to use:** `apps/web` UI — routes, `@repo/ui`, TanStack Start server functions and collections, forms, Tailwind layout rules, design-system updates, and **`useEffect` / `useMountEffect` policy**.

Toolchain, commands, and CI

3940
from latitude-dev/latitude-llm

**When to use:** Installing dependencies, running dev/build/test/lint, filtering packages, single-test runs, git hooks, preparing a clone (`.env.development` / `.env.test`), or **Docker-backed local services and dev servers**.