Hein 3e64f7ae2a
Some checks failed
Integration Tests / integration-test (push) Failing after -23m59s
feat(testing): add full integration test suite
This commit introduces a comprehensive integration test suite for the pgsql-broker.

The test suite includes:
- A Docker/Podman environment for running a PostgreSQL database, managed via a .
- Integration tests that cover the broker's lifecycle, including job creation, execution, and instance management.
- A GitHub Actions workflow to automate the execution of all tests on push and pull requests.
- A dedicated test configuration file () and helper test files.

refactor(worker): fix job processing transaction
- The worker's job processing now uses a single transaction to fetch and run a job, resolving a race condition where jobs were not in the 'running' state when being executed.
- The broker's database instance registration is now more robust, handling cases where another instance is already active.

The Makefile has been significantly updated to orchestrate the entire test flow, including setting up the database, starting/stopping the broker, and running unit and integration tests separately.
2026-01-02 23:08:17 +02:00
2026-01-02 17:38:39 +00:00

PostgreSQL Broker

A robust, event-driven job processing system for PostgreSQL that uses LISTEN/NOTIFY for real-time job execution. It supports multiple queues, priority-based scheduling, and can be used both as a standalone service or as a Go library.

Features

  • Multi-Database Support: Single broker process can manage multiple database connections
  • Event-Driven: Uses PostgreSQL LISTEN/NOTIFY for instant job notifications
  • Multiple Queues: Support for concurrent job processing across multiple queues per database
  • Priority Scheduling: Jobs can be prioritized for execution order
  • Job Dependencies: Jobs can depend on other jobs being completed first
  • Adapter Pattern: Clean interfaces for database and logging (easy to extend)
  • Standalone or Library: Use as a CLI tool or integrate into your Go application
  • Configuration Management: Viper-based config with support for YAML, JSON, and environment variables
  • Graceful Shutdown: Proper cleanup and job completion on shutdown
  • Instance Tracking: Monitor active broker instances through the database
  • Single Instance Per Database: Enforces one broker instance per database to prevent conflicts
  • Embedded SQL Installer: Database schema embedded in binary with built-in install command

Architecture

The broker supports multi-database architecture where a single broker process can manage multiple database connections. Each database has its own instance with dedicated queues, but only ONE broker instance is allowed per database.

┌─────────────────────────────────────────────────────────────────┐
│                      Broker Process                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                   │
│  ┌────────────────────────────┐  ┌───────────────────────────┐ │
│  │  Database Instance (DB1)   │  │  Database Instance (DB2)  │ │
│  ├────────────────────────────┤  ├───────────────────────────┤ │
│  │ ┌────┐ ┌────┐ ┌────┐      │  │ ┌────┐ ┌────┐            │ │
│  │ │ Q1 │ │ Q2 │ │ QN │      │  │ │ Q1 │ │ Q2 │            │ │
│  │ └────┘ └────┘ └────┘      │  │ └────┘ └────┘            │ │
│  │                            │  │                           │ │
│  │ ┌────────────────────────┐│  │ ┌────────────────────────┐│ │
│  │ │  PostgreSQL Adapter    ││  │ │  PostgreSQL Adapter    ││ │
│  │ │  - Connection Pool     ││  │ │  - Connection Pool     ││ │
│  │ │  - LISTEN/NOTIFY       ││  │ │  - LISTEN/NOTIFY       ││ │
│  │ └────────────────────────┘│  │ └────────────────────────┘│ │
│  └────────────┬───────────────┘  └──────────┬────────────────┘ │
│               │                              │                   │
└───────────────┼──────────────────────────────┼───────────────────┘
                │                              │
                ▼                              ▼
    ┌──────────────────────┐      ┌──────────────────────┐
    │  PostgreSQL (DB1)    │      │  PostgreSQL (DB2)    │
    │  - broker_jobs       │      │  - broker_jobs       │
    │  - broker_queueinstance│    │  - broker_queueinstance│
    │  - broker_schedule   │      │  - broker_schedule   │
    └──────────────────────┘      └──────────────────────┘

Key Points:

  • One broker process can manage multiple databases
  • Each database has exactly ONE active broker instance
  • Each database instance has its own queues and workers
  • Validation prevents multiple broker processes from connecting to the same database
  • Different databases can have different queue counts

Installation

From Source

git clone git.warky.dev/wdevs/pgsql-broker
cd pgsql-broker
make build

The binary will be available in bin/pgsql-broker.

As a Library

go get git.warky.dev/wdevs/pgsql-broker

Quick Start

1. Setup Database

Install the required tables and stored procedures:

# Using the CLI (recommended)
./bin/pgsql-broker install --config broker.yaml

# Or with make
make sql-install

# Verify installation
./bin/pgsql-broker install --verify-only --config broker.yaml

# Or manually with psql:
psql -f pkg/broker/install/sql/tables/00_install.sql
psql -f pkg/broker/install/sql/procedures/00_install.sql

2. Configure

Create a configuration file broker.yaml:

databases:
  - name: db1
    host: localhost
    port: 5432
    database: broker_db1
    user: postgres
    password: your_password
    sslmode: disable
    queue_count: 4

  # Optional: add more databases
  - name: db2
    host: localhost
    port: 5432
    database: broker_db2
    user: postgres
    password: your_password
    sslmode: disable
    queue_count: 2

broker:
  name: pgsql-broker
  enable_debug: false

logging:
  level: info
  format: json

Note: Each database requires a unique name identifier and can have its own queue_count configuration.

3. Run the Broker

# Using the binary
./bin/pgsql-broker start --config broker.yaml

# Or with make
make run

# Or with custom log level
./bin/pgsql-broker start --log-level debug

4. Add a Job

SELECT broker_add_job(
    'My Job',                    -- job_name
    'SELECT do_something()',     -- execute_str
    1,                           -- job_queue (default: 1)
    0,                           -- job_priority (default: 0)
    'sql',                       -- job_language (default: 'sql')
    NULL,                        -- run_as
    NULL,                        -- user_login
    NULL                         -- schedule_id
);

Usage as a Library

package main

import (
    "git.warky.dev/wdevs/pgsql-broker/pkg/broker"
    "git.warky.dev/wdevs/pgsql-broker/pkg/broker/adapter"
    "git.warky.dev/wdevs/pgsql-broker/pkg/broker/config"
)

func main() {
    // Load config
    cfg, _ := config.LoadConfig("broker.yaml")

    // Create logger
    logger := adapter.NewSlogLogger(slog.LevelInfo)

    // Create database adapter
    dbAdapter := adapter.NewPostgresAdapter(cfg.Database.ToPostgresConfig(), logger)

    // Create and start broker
    instance, _ := broker.New(cfg, dbAdapter, logger, "1.0.0")
    instance.Start()

    // ... wait for shutdown signal ...

    instance.Stop()
}

See the examples directory for complete examples.

Database Schema

Tables

  • broker_queueinstance: Tracks active broker queue instances (one per database)
  • broker_jobs: Job queue with status tracking
  • broker_schedule: Scheduled jobs (cron-like functionality)

Stored Procedures

  • broker_get: Fetch the next job from a queue
  • broker_run: Execute a job
  • broker_set: Set runtime options (user, application_name, etc.)
  • broker_add_job: Add a new job to the queue
  • broker_register_instance: Register a broker instance
  • broker_ping_instance: Update instance heartbeat
  • broker_shutdown_instance: Mark instance as shutdown

Configuration Reference

See broker.example.yaml for a complete configuration example.

Database Settings

The databases array can contain multiple database configurations. Each entry supports:

Setting Description Default
name Unique identifier for this database Required
host PostgreSQL host localhost
port PostgreSQL port 5432
database Database name Required
user Database user Required
password Database password -
sslmode SSL mode disable
max_open_conns Max open connections 25
max_idle_conns Max idle connections 5
conn_max_lifetime Connection max lifetime 5m
conn_max_idle_time Connection max idle time 10m
queue_count Number of queues for this database 4

Broker Settings

Global settings applied to all database instances:

Setting Description Default
name Broker instance name pgsql-broker
fetch_query_que_size Jobs per fetch cycle 100
queue_timer_sec Seconds between polls 10
queue_buffer_size Job buffer size 50
worker_idle_timeout_sec Worker idle timeout 10
notify_retry_seconds NOTIFY retry interval 30s
enable_debug Enable debug logging false

Development

Building

make build       # Build the binary
make clean       # Clean build artifacts
make deps        # Download dependencies
make fmt         # Format code
make vet         # Run go vet
make test        # Run tests

Project Structure

pgsql-broker/
├── cmd/broker/          # CLI application
├── pkg/broker/          # Core broker package
│   ├── adapter/         # Database & logger interfaces
│   ├── config/          # Configuration management
│   ├── models/          # Data models
│   ├── queue/           # Queue management
│   ├── worker/          # Worker implementation
│   └── install/         # Database installer with embedded SQL
│       └── sql/         # SQL schema (embedded in binary)
│           ├── tables/  # Table definitions
│           └── procedures/ # Stored procedures
├── examples/            # Usage examples
└── Makefile             # Build automation

Contributing

Contributions are welcome! Please ensure:

  • Code is formatted with go fmt
  • Tests pass with go test ./...
  • Documentation is updated

License

See LICENSE file for details.

Description
PostgreSQL Broker
Readme Apache-2.0 89 KiB
Languages
Go 69.4%
PLpgSQL 23%
Makefile 7.6%