Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ const getURL = () => {


export const metadata: Metadata = {
title: "Apalis - background task and message processing library for Rust",
title: "Apalis - background jobs, tasks and messages processing library for Rust",
description:
"Simple, extensible multithreaded background task and message processing library for Rust",
"Simple, extensible multithreaded background jobs, tasks and messages processing library for Rust",
openGraph: {
images: `${getURL()}images/og.png`,
},
Expand Down
63 changes: 63 additions & 0 deletions app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { MetadataRoute } from 'next'
import { allDocsPages, allBlogPosts, allTutorials } from 'contentlayer/generated'

export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://apalis.dev'

const docsUrls: MetadataRoute.Sitemap = allDocsPages.map((doc) => ({
url: `${baseUrl}${doc.urlPath}`,
lastModified: doc.lastEdited ? new Date(doc.lastEdited) : new Date(),
changeFrequency: 'weekly' as const,
priority: 0.7,
}))

const blogUrls: MetadataRoute.Sitemap = allBlogPosts.map((post) => ({
url: `${baseUrl}${post.urlPath}`,
lastModified: new Date(post.date),
changeFrequency: 'monthly' as const,
priority: 0.6,
}))

const tutorialUrls: MetadataRoute.Sitemap = allTutorials.map((tutorial) => ({
url: `${baseUrl}${tutorial.urlPath}`,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 0.65,
}))

// Static pages
const staticUrls: MetadataRoute.Sitemap = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'daily' as const,
priority: 1,
},
{
url: `${baseUrl}/docs`,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 0.8,
},
{
url: `${baseUrl}/pricing`,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 0.8,
},
{
url: `${baseUrl}/blog`,
lastModified: new Date(),
changeFrequency: 'daily' as const,
priority: 0.8,
},
{
url: `${baseUrl}/tutorials`,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 0.8,
},
]

return [...staticUrls, ...docsUrls, ...blogUrls, ...tutorialUrls]
}
15 changes: 11 additions & 4 deletions components/sections/features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import CompatibleBackends from "./features/compatible-backends"
import Middleware from "./features/middleware"
import Observability from "./features/observability"
import Workflows from "./features/workflows"
import Link from "next/link"

const FeatureCard = ({ title, description, Component }) => (
const FeatureCard = ({ title, description, Component, href }) => (
<div className="overflow-hidden rounded-md border border-white/20 flex flex-col justify-start items-start relative">
<div
className="absolute inset-0 rounded-md"
Expand All @@ -19,10 +20,10 @@ const FeatureCard = ({ title, description, Component }) => (

<div className="self-stretch p-6 flex flex-col justify-start items-start gap-2 relative z-10">
<div className="self-stretch flex flex-col justify-start items-start gap-1.5">
<p className="self-stretch text-foreground font-normal leading-7">
<Link href={href} className="self-stretch text-foreground font-normal leading-7">
{title} <br />
<span className="text-muted-foreground">{description}</span>
</p>
</Link>
</div>
</div>
<div className="self-stretch h-72 relative -mt-0.5 z-10">
Expand All @@ -37,31 +38,37 @@ export function Features() {
title: "Functional",
description: "Functional programming approach with dependency injection with no macros.",
Component: FunctionalApproach,
href: "/docs/guides/tasks/introduction"
},
{
title: "Web-based UI",
description: "Intuitive web interface for managing and monitoring background tasks.",
Component: WebBasedUI,
href: "/docs/products/web-board"
},
{
title: "Compatible with popular backends",
description: "Easily connect your projects to databases and services.",
Component: CompatibleBackends,
href: "/docs/introduction/architecture#the-backend"
},
{
title: "Flexible Middleware",
description: "Provides middleware support build on top of tower",
Component: Middleware,
href: "/docs/guides/workers/middleware"
},
{
title: "Workflow Orchestration",
title: "Workflow Orchestration",
description: "Coordinate complex background tasks with ease.",
Component: Workflows,
href: "/docs/guides/workflows"
},
{
title: "Observability",
description: "Gain insights into your background tasks with built-in instrumentation.",
Component: Observability,
href: "/docs/integrations/tracing"
},
]

Expand Down
18 changes: 9 additions & 9 deletions content/docs/100-introduction/100-overview.mdx
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
---
title: Overview
navTitle: Overview
excerpt: Apalis is a simple yet powerful Rust library for building reliable, scalable, and multithreaded background task and message processing systems.
excerpt: Apalis is a simple yet powerful Rust library for building durable, distributed and multithreaded background jobs, tasks and messages processing systems.
bottomNavigation: pagination
---

apalis — Scalable background task processing in Rust, made simple and extensible.

## What is apalis?

Apalis is a simple yet powerful Rust library for building reliable, scalable, and multithreaded background task and message processing systems.
Apalis is a simple yet powerful Rust library for building durable, distributed and multithreaded background jobs, tasks and messages processing systems.

## Core Features

Some of the main apalis features include:

| **Feature** | **Description** |
|---------------------|----------------------------------------------------------------------------------------------------------------------|
| **Clean API** | A clean, macro-free API that promotes a predictable and functional approach to task handling. |
| **Tower Integration** | Tasks are built on `tower::Service`, giving access to the rich ecosystem of Tower middleware and utilities. |
| **Clean API** | A clean, macro-free API that promotes a predictable and [functional approach to task handling](docs/guides/tasks/introduction#async-function). |
| **Tower Integration** | Tasks are built on [`tower::Service`](https://docs.rs/tower-service/latest/tower_service/trait.Service.html), giving access to the rich ecosystem of [tower middleware](https://docs.rs/tower/latest/tower/#the-tower-ecosystem) and utilities. |
| **Stream-Based Sources** | Any type that implements `Stream` can act as a task source — queues, channels, or custom pipelines. |
| **Runtime Agnostic** | Works with both `tokio` and `async-std`, offering flexibility across async runtimes. |
| **High Concurrency** | Supports configurable workers, task queues, and thread pools for optimal performance. |
| **High Concurrency** | Supports configurable [workers](/docs/guides/workers/introduction), [queues](/docs/guides/backend/introduction), and multi-threading for optimal performance. |
| **Extensibility** | Modular and flexible, allowing easy addition of new features or connectors tailored to your needs. |
| **Scalability** | Efficiently handles growing workloads with a multithreaded processing model. |
| **Reliability** | Built-in retry strategies and robust error handling ensure consistent task execution. |
| **Integration Ready** | Out-of-the-box support for Redis, PostgreSQL, and other common systems. |
| **Observability** | Detailed logging, metrics, and tracing help you monitor and debug task workflows. |
| **Scalability** | Efficiently handles growing workloads with a distributed processing model. |
| **Reliability** | Built-in [retry strategies](/docs/guides/tasks/error-handling#retries) and [robust error handling](/docs/guides/tasks/error-handling#overview) ensure consistent task execution. |
| **Integration Ready** | Out-of-the-box support for [Redis, PostgreSQL, and other common backends](/docs/guides/backend/introduction#implementations). |
| **Observability** | Detailed logging, metrics, and [tracing](/docs/integrations/tracing) help you monitor and debug task workflows. |

## How to Use These Docs

Expand Down
8 changes: 4 additions & 4 deletions content/docs/100-introduction/200-quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ async fn send_email(email: Email) {
println!("Sending email to {:?}", email);
}
```
This defines an async function `send_email` — the task handler — which receives an `Email` message and performs the work associated with it.
This defines an async function `send_email` — [the task handler](/docs/guides/tasks/introduction#async-function) — which receives an `Email` message and performs the work associated with it.
The function returns a `Result<(), E>` where `E: StdError`.

### Setting Up a Worker

With the task handler in place, we can now configure the worker that will fetch and execute these tasks.
With the task handler in place, we can now configure the [worker](/docs/guides/workers/introduction) that will fetch and execute these tasks.

A worker is responsible for polling the backend for tasks and executing them using the handler function.
A worker is responsible for polling the [backend](/docs/guides/backend/introduction) for tasks and executing them using the handler function.

```rust name="worker" mode="inline"
WorkerBuilder::new("email_worker")
Expand All @@ -96,7 +96,7 @@ The worker continuously polls the tasks, executing them as they become available

### Enqueue a Task

With the worker and backend in place, you can now enqueue a message to be processed.
With the worker and backend in place, you can now [enqueue a task](/docs/guides/backend/pushing-tasks) to be processed.

In this example, we’ll push a task to the MemoryStorage-backed queue inside the same binary, right before the worker runs.

Expand Down
22 changes: 11 additions & 11 deletions content/docs/100-introduction/300-architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ excerpt: Apalis is built around a small set of composable abstractions — a bac
bottomNavigation: pagination
---

Apalis is designed around a small number of composable abstractions that fit together cleanly. Once you understand the three core layers — **backends**, **workers**, and **middleware** — every other concept in the documentation is a natural extension of them.
Apalis is designed around a small number of composable abstractions that fit together cleanly. Once you understand the three core layers — [**backends**](/docs/guides/backend/introduction), [**workers**](/docs/guides/workers/introduction), and [**middleware**](/docs/guides/workers/middleware) — every other concept in the documentation is a natural extension of them.

This page gives you a structural map of the whole system before you dive into the details.

Expand All @@ -23,8 +23,8 @@ flowchart LR

Three things happen in every Apalis deployment:

1. **Tasks are pushed** into a backend via `TaskSink` — encoded, wrapped in a `Task` envelope, and written to storage
2. **A worker polls** the backend for tasks, drives them through a middleware stack, and hands them to your handler function
1. [**Tasks are pushed**](/docs/guides/backend/pushing-tasks) into a backend via `TaskSink` — encoded, wrapped in a `Task` envelope, and written to storage
2. **A worker polls** the backend for tasks, drives them through a [middleware stack](/docs/guides/workers/middleware), and hands them to your handler function
3. **The backend receives heartbeats** from the worker so it can detect stalled workers and requeue their tasks

Everything else — workflows, shared connections, observability, piping — is built on top of these three interactions.
Expand All @@ -35,7 +35,7 @@ Everything else — workflows, shared connections, observability, piping — is

### The Task Envelope

Every job in Apalis is wrapped in a `Task<Args, Context, IdType>` before it touches any backend. The envelope carries three things:
Every job in Apalis is wrapped in a [`Task<Args, Context, IdType>`](https://crates.io/crates/apalis-core/1.0.0-rc.7#tasks) before it touches any backend. The envelope carries three things:

- **`Args`** — your job data (an email address, a user ID, a struct)
- **`Context`** — per-task metadata: attempt count, scheduled time, priority, tracing context
Expand Down Expand Up @@ -73,15 +73,15 @@ Currently supported backends:
| `apalis-mysql` | MySQL / MariaDB | ✅ Persistent |
| `apalis-sqlite` | SQLite | ✅ Persistent |
| `apalis-redis` | Redis | ✅ Persistent |
| `apalis-cron` | In-memory schedule | ⚡ Ephemeral — use `pipe_to` for durability |
| `apalis-cron` | In-memory schedule | ⚡ Ephemeral — use [`pipe_to`](/docs/advanced-concepts/piping-streams) for durability |
| `apalis-amqp` | AMQP broker | ✅ Persistent |
| `apalis-nats` | NATS | ✅ Persistent |

---

### The Worker

A worker drives a backend's task stream through a Tower service stack and into your handler. It is built with `WorkerBuilder`:
A worker drives a backend's task stream through a Tower service stack and into your handler. It is built with [`WorkerBuilder`](https://docs.rs/apalis-core/1.0.0-rc.7/apalis_core/worker/builder/index.html):
```
WorkerBuilder::new("name")
.backend(B) → sets the task source
Expand Down Expand Up @@ -111,7 +111,7 @@ flowchart LR
T1[TraceLayer] --> TO1[TimeoutLayer] --> R1[RetryLayer] --> H[Handler] --> R2[RetryLayer] --> TO2[TimeoutLayer] --> T2[TraceLayer]
```

Because middleware is composable Tower services, anything in the Tower ecosystem — rate limiting, circuit breaking, load shedding, custom instrumentation — works without modification. See [Middleware Order](/docs/middleware-order) for guidance on stacking layers correctly.
Because middleware is composable Tower services, anything in the Tower ecosystem — [rate limiting](https://docs.rs/apalis/1.0.0-rc.7/apalis/layers/trait.WorkerBuilderExt.html#tymethod.rate_limit), [circuit breaking](/docs/guides/workers/middleware#circuit-breaker), [load shedding](https://docs.rs/tower/latest/tower/load_shed/index.html), custom instrumentation — works without modification. See [Middleware Order](/docs/guides/workers/order-of-middleware) for guidance on stacking layers correctly.

---

Expand All @@ -128,7 +128,7 @@ Vec<u8> → stored in backend
Email → handler receives this
```

Apalis ships `JsonCodec` (default), `MsgPackCodec`, and `BincodeCodec`. The codec is fixed per backend via `BackendExt::Codec`. See [Codecs](/docs/guides/backend/codecs).
Apalis ships [`JsonCodec`](https://docs.rs/apalis-codec/latest/apalis_codec/json/struct.JsonCodec.html) (default), `MsgPackCodec`, and `BincodeCodec`. The codec is fixed per backend via `BackendExt::Codec`. See [Codecs](/docs/guides/backend/codecs).

---

Expand All @@ -146,14 +146,14 @@ When multiple workers share the same data store, `MakeShared` lets them derive i

### Piping — `PipeExt`

Any `Stream<Item = Result<Args, E>>` can be routed into a backend via `.pipe_to()`. The resulting `Pipe` implements `Backend`, so the worker sees a unified task stream without knowing the upstream source was a cron schedule, a CDC feed, or a channel. See [Piping Streams](/docs/advanced-concepts/piping-streams).
Any `Stream<Item = Result<Args, E>>` can be routed into a backend via [`.pipe_to()`](/docs/advanced-concepts/piping-streams). The resulting `Pipe` implements `Backend`, so the worker sees a unified task stream without knowing the upstream source was a cron schedule, a CDC feed, or a channel. See [Piping Streams](/docs/advanced-concepts/piping-streams).

### Workflows

For multi-step jobs, `apalis_workflow` provides two higher-level backend types that both implement `Backend` and slot into a standard `WorkerBuilder`:

- **`Workflow`** — a linear pipeline of typed async steps connected with combinators (`and_then`, `filter_map`, `fold`, etc.)
- **`DagFlow`** — a directed acyclic graph where independent steps run in parallel and dependent steps wait only for their specific inputs
- [**`Workflow`**](/docs/guides/workflows/sequential-workflow) — a linear pipeline of typed async steps connected with combinators (`and_then`, `filter_map`, `fold`, etc.)
- [**`DagFlow`**](/docs/guides/workflows/dag-workflow) — a directed acyclic graph where independent steps run in parallel and dependent steps wait only for their specific inputs

See [Sequential Workflows](/docs/guides/workflows/sequential-workflow) and [DAG Workflows](/docs/guides/workflows/dag-workflow).

Expand Down
8 changes: 8 additions & 0 deletions content/docs/100-introduction/400-use-cases.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ Apalis can be used to build robust data pipelines that process large volumes of

Workers can process jobs concurrently, enabling efficient handling of high-throughput workloads.

Learn more about [Sequential Workflows](/docs/guides/workflows/sequential-workflow) which provides durable and distributed pipelined processings

---

### Webhook Handling and Event Processing
Expand All @@ -78,6 +80,8 @@ Some operations are computationally expensive and should not block the main appl

By offloading these tasks to workers, your application remains responsive and scalable.

Learn more about [Parallelizing tasks](/docs/guides/workers/middleware#parallelize) and [Long Running Tasks](/docs/guides/workers/middleware#long-running-jobs).

---

### Task Orchestration and Workflows
Expand All @@ -90,6 +94,8 @@ Apalis can coordinate multi-step workflows where tasks depend on each other. Thi

You can model workflows as a series of jobs, where each step enqueues the next, enabling flexible and composable pipelines.

Learn more about [Sequential Workflows](/docs/guides/workflows/sequential-workflow) and [DAG Workflows](/docs/guides/workflows/dag-workflow).

---

### Retry and Failure Handling
Expand All @@ -103,6 +109,8 @@ Failures are inevitable in distributed systems. Apalis provides mechanisms to ha

This ensures that your system remains robust even in the face of transient failures.

See [Retries](/docs/guides/tasks/error-handling#retries) and [Catching Panics](/docs/guides/tasks/error-handling#catching-panics) for more.

---

### Rate-Limited and External API Calls
Expand Down
Loading
Loading