The Postgres-Powered Pacemaker: Inside duplicati/console-scheduler

How a legacy backup system extracted its internal clock into a zero-bloat .NET microservice using SQL as a message bus.

6 min read • View on GitHub • More from duplicati

A split illustration contrasting a bloated, multi-engine machine with a sleek, single-spring clockwork mechanism. This represents the architectural choice between relying on multiple external message brokers versus a single integrated database.
By using PostgreSQL for both storage and messaging, the scheduler avoids the operational overhead of running separate Redis or RabbitMQ containers.
Key Takeaways

The Infrastructure Diet

Modern microservices often default to adding dedicated message brokers like RabbitMQ or Kafka. The Duplicati console-scheduler explicitly rejects this bloat. Instead, the team built a highly optimized .NET 9 microservice that uses PostgreSQL as both its database and its message bus.

By leveraging MassTransit's SQL transport capabilities, the scheduler eliminates the need for sidecar containers. This architectural pragmatism ensures that users only need to manage a single database dependency to keep the entire distributed system pulsing.

Translating Time into Data

The core function of the scheduler is to translate the passage of time into actionable data. Standard cron expressions in Quartz.NET are used to trigger events. When a specific time threshold is reached, Quartz hands off a typed record to MassTransit.

These records are then serialized and inserted directly into a PostgreSQL table. This table acts as the queue, with transactions ensuring that messages are locked, processed, and acknowledged without external broker dependencies. Developers even included a hidden endpoint to manually emit these payloads for rapid testing.

The Pacemaker Pipeline: Temporal events are translated into durable database messages.

The InitContainer Pattern

Deployment friction is a common issue in decoupled architectures. The Duplicati scheduler solves this by acting as its own bootstrapper. Using the .NET 9 Slim Web Builder, the application probes the database for required tables on startup.

If the schema is missing, an embedded SQL script is executed directly. This setup is perfectly suited for Kubernetes InitContainers. The service can be run with an initialization flag, complete its database migrations, and exit cleanly before the main application components spin up.

A close-up illustration of a mechanical hand inserting a key into a solid ignition cylinder, bypassing a tangled fuse box in the background.
The application bypasses heavy ORM frameworks, using raw embedded SQL to execute precise, self-healing database migrations.

Escaping the Monolith

For years, Duplicati has operated as a monolithic desktop application. The console-scheduler represents a deliberate shift toward a cloud-native ecosystem. By surgically extracting the internal clock into a standalone service, the project lays the groundwork for a more resilient architecture.

Duplicati has a built-in scheduler that can be used to run backups automatically at specific times or intervals.

Duplicati Documentation, Official Project Documentation · Scheduling backups - Duplicati

While the legacy application relied on internal timers, the new microservice approach ensures that scheduling logic is isolated, testable, and scalable. It is a calculated evolution that modernizes the codebase while strictly managing infrastructure complexity.