Dartvel, home
Docs
Features
Studio
Cloud
Compared

Search the site

GitHub
pub.dev

GETTING STARTED

Getting started
Existing Flutter apps
Existing Native apps
Run on your phone

APP

UI and styling
Routing
State
Accessibility
Keyboard shortcuts
Localization
Devices and desktop
Native device access
Media, 3D and XR

DATA

Data models
Forms
Search
Sync and offline
Import and export
Change capture
Database
Cache
File storage
Images
Privacy and erasure

BACKEND

Backend functions
Auth and sessions
Authorization
Queues and jobs
Workers and memory
Notifications and mail
Outbound HTTP
AI
Webhooks
GraphQL and OpenAPI
API keys and OAuth
Multi-tenancy
Billing and commerce
Modules

OPERATIONS

Edge security
Secrets and environments
Monitoring
Releases

SHIPPING

Build targets
Telegram Mini Apps
Static web hosting
Servers and deploying

REFERENCE

Testing
CLI reference
Coding agents

BACKEND

Queues and jobs

Send email, resize images and call slow APIs after the response, with retries.

A job is a small class. Dispatch it and a worker runs it.

ON THIS PAGE

Declare a job and its handler

Dispatch a job

Run workers

Where jobs are kept

Jobs keep their tenant

Schedule work with cron

Status

Declare a job and its handler

// lib/jobs/welcome.dart
// The generated job types, without Flutter, so a worker can run it.
import '../dartvel_client/jobs.g.dart';
import 'package:dartvel_core/dartvel.dart';

@DVJob(queue: 'mail', maxAttempts: 5, backoffSeconds: 60)
class const _SendWelcomeEmail({required final String userId});

@DVJob.handler()
Future<void> _handleSendWelcomeEmail(SendWelcomeEmail job) =>
    sendWelcomeEmail(job.userId);

Copy code to clipboard

@DVJob takes queue, priority, maxAttempts (3) and backoffSeconds (30).

Generation writes the public SendWelcomeEmail with dispatch().

A handler that uses DV runs in the app only. Write it against dartvel_core so a worker can run it.

Dispatch a job

await SendWelcomeEmail(userId: 'user-1').dispatch();

// Override the declared settings for one dispatch.
await SendWelcomeEmail(userId: 'user-2').dispatch(
  queue: 'priority-mail',
  maxAttempts: 10,
);

Copy code to clipboard

From a backend function, dispatch and return straight away.

// lib/backend/functions/signup.post.dart
import 'package:dartvel_core/dartvel.dart';

import '../../dartvel_client/jobs.g.dart';

@DVBackendFunction()
Future<Map<String, Object?>> _signup(String userId) async {
  // The response goes out now. A worker sends the email.
  await SendWelcomeEmail(userId: userId).dispatch();
  return <String, Object?>{'queued': true};
}

Copy code to clipboard

Run workers

Start the generated backend with these environment variables and it works jobs instead of serving HTTP.

DARTVEL_ROLE=worker
DARTVEL_QUEUE=mail,default
DATABASE_URL=postgres://app@db.internal/app

Copy code to clipboard

A worker needs DATABASE_URL and at least one handler, or it refuses to start.

A failed job goes back on its queue until maxAttempts, then to dead letters. Only the SQS and Pub/Sub adapters wait out the backoff first.

DARTVEL_HEALTH_PORT serves /healthz for a worker.

Work a queue by hand

dartvel queue work --queue mail --max-jobs 10

Copy code to clipboard

This runs your project's worker, so DATABASE_URL must be set in your shell. The failed, retry and flush subcommands still read the CLI's own empty queue, so use the calls below for those.

// A worker drains the queue. It is a process, not a line in a page:
//
//     dartvel queue work --queue mail --max-jobs 10
//
// What an application does is look at what failed.
final List<DVJobEnvelope<DVJobPayload>> dead = await DV.Jobs.deadLetters('mail');
for (final DVJobEnvelope<DVJobPayload> job in dead) {
  DV.log('${job.id} failed ${job.attempts} times: ${job.lastError}');
  await DV.Jobs.retry(job.id); // or DV.Jobs.discard(job.id)
}

Copy code to clipboard

Where jobs are kept

With DATABASE_URL set, jobs are durable with no setup. The generated backend keeps them in that database, and every web, worker and cron process of the deployment shares them.

Generation writes how each job is encoded from its @DVJob class, so there is nothing to register.

Without DATABASE_URL, jobs stay in the memory of the process that dispatched them, except in a web-server binary, which keeps them in the SQLite file beside it.

Your database

How it is chosen: DATABASE_URL, with no setup

Memory

How it is chosen: In tests

Redis, Amazon SQS, RabbitMQ, Google Pub/Sub, Kafka

How it is chosen: Not from configuration yet

Adapters for the other brokers exist, but nothing in pubspec.yaml selects one yet. See the status below.

Jobs keep their tenant

dispatch() records the current tenant. The worker runs the handler inside that tenant, so tenant-scoped models and cache keys behave as they did for the request.

Schedule work with cron

// A cron function is public. Every other generation input is private.
@DVBackendCron('0 3 * * *', catchUp: true)
Future<void> nightlyRollup() => rollUpYesterday();

Copy code to clipboard

catchUp: true runs a missed occurrence after a restart.

Schedules tick in a process with no role or DARTVEL_ROLE=cron.

With DATABASE_URL set, each occurrence is claimed in the database, so two cron processes do not both run it. Without one, a cron process refuses to start unless DARTVEL_SCHEDULE_LEASE=none says it is the only one.

Partial

Spec section: Scheduling

Planned work and implementation limits

No per-target capability report or doctor check for schedules.

Status

Partial

Spec section: Queues, Jobs, and Signals

Planned work and implementation limits

Delayed jobs, exponential backoff, unique jobs and pausing a queue are not built.

The queue failed, retry and flush commands act on the CLI's own process queue.

Only the database is chosen from configuration. Redis, SQS, AMQP, Pub/Sub and Kafka have adapters, but no pubspec.yaml key selects one.

PREVIOUS Authorization Policies under DV.Auth.authorization
NEXT Workers and memory Heavy work on other cores, and memory reserved up front
GitHub
pub.dev
npm
Acknowledgements
Privacy
Terms

FSL-1.1-MIT licensed. Built with Dartvel.

Dartvel is made by

SigmaDev Digital

To the bottom