A Postgres-native durable workflow system

yogthos1 pts0 comments

Absurd - Absurd

Skip to content

Guide

SDKs

Patterns

Tools

Absurd

Absurd is a Postgres-native durable workflow system. It moves the complexity of<br>durable execution into the database layer via stored procedures, keeping SDKs<br>lightweight and language-agnostic. The core principle is to handle tasks that<br>may run for minutes, days, or years without losing state.

All you need is a Postgres database and the single<br>absurd.sql<br>schema file. No extra services, no message brokers, no coordination layer.<br>SDKs stay simple too.

… because it's absurd how much you can over-design such a simple thing.

How It Works

A task dispatches onto a queue from where a worker picks it up.<br>Tasks are subdivided into steps that act as checkpoints. Once a step<br>completes successfully its return value is persisted and the step won't execute<br>again. If a task fails, it retries from the last checkpoint.

Tasks can also sleep (suspend until a time) or await events (suspend<br>until a named event is emitted). Events are cached — first emit wins — making<br>them race-free.

TypeScriptPythonGo

import { Absurd } from 'absurd-sdk';

const app = new Absurd();

app.registerTask({ name: 'order-fulfillment' }, async (params, ctx) => {<br>const payment = await ctx.step('process-payment', async () => {<br>return { paymentId: `pay-${params.orderId}`, amount: params.amount };<br>});

const shipment = await ctx.awaitEvent(<br>`shipment.packed:${params.orderId}`,<br>);

await ctx.step('send-notification', async () => {<br>return {<br>sentTo: params.email,<br>trackingNumber: shipment.trackingNumber,<br>};<br>});

return {<br>orderId: params.orderId,<br>payment,<br>trackingNumber: shipment.trackingNumber,<br>};<br>});

await app.startWorker();

from absurd_sdk import Absurd

app = Absurd()

@app.register_task(name="order-fulfillment")<br>def process_order(params, ctx):<br>def process_payment():<br>return {<br>"payment_id": f"pay-{params['order_id']}",<br>"amount": params["amount"],

payment = ctx.step("process-payment", process_payment)

shipment = ctx.await_event(f"shipment.packed:{params['order_id']}")

def send_notification():<br>return {<br>"sent_to": params["email"],<br>"tracking_number": shipment["tracking_number"],

ctx.step("send-notification", send_notification)

return {<br>"order_id": params["order_id"],<br>"payment": payment,<br>"tracking_number": shipment["tracking_number"],

app.start_worker()

package main

import (<br>"context"<br>"log"

"github.com/earendil-works/absurd/sdks/go/absurd"<br>_ "github.com/jackc/pgx/v5/stdlib"

type OrderFulfillmentParams struct {<br>OrderID string `json:"order_id"`<br>Amount int `json:"amount"`<br>Email string `json:"email"`

type ShipmentEvent struct {<br>TrackingNumber string `json:"tracking_number"`

var orderFulfillmentTask = absurd.Task(<br>"order-fulfillment",<br>func(<br>ctx context.Context,<br>params OrderFulfillmentParams,<br>) (map[string]any, error) {<br>payment, err := absurd.Step(<br>ctx,<br>"process-payment",<br>func(ctx context.Context) (map[string]any, error) {<br>return map[string]any{<br>"payment_id": "pay-" + params.OrderID,<br>"amount": params.Amount,<br>}, nil<br>},<br>if err != nil {<br>return nil, err

shipment, err := absurd.AwaitEvent[ShipmentEvent](<br>ctx,<br>"shipment.packed:"+params.OrderID,<br>if err != nil {<br>return nil, err

if _, err := absurd.Step(<br>ctx,<br>"send-notification",<br>func(ctx context.Context) (map[string]any, error) {<br>return map[string]any{<br>"sent_to": params.Email,<br>"tracking_number": shipment.TrackingNumber,<br>}, nil<br>},<br>); err != nil {<br>return nil, err

return map[string]any{<br>"order_id": params.OrderID,<br>"payment": payment,<br>"tracking_number": shipment.TrackingNumber,<br>}, nil<br>},

func main() {<br>app, err := absurd.New(absurd.Options{<br>QueueName: "default",<br>DriverName: "pgx",<br>})<br>if err != nil {<br>log.Fatal(err)<br>defer app.Close()

app.MustRegister(orderFulfillmentTask)<br>if err := app.RunWorker(context.Background()); err != nil {<br>log.Fatal(err)

Quick Links

Quickstart — install the schema, create a queue, run your first task

Concepts — what durable execution is, plus tasks, steps, runs, events, and retry semantics

Storage — choose unpartitioned vs partitioned queues and automate partition lifecycle

Cleanup and Retention — set retention policies and automate cleanup with SQL, absurdctl, or cron

Comparison — where Absurd fits relative to PGMQ, Cadence, Temporal, Inngest, and DBOS

Patterns — practical recipes for common workflow and scheduling setups

Deploying and Rolling Rollouts — safely introduce new task names during rolling deploys

SDKs — available language SDKs

Tools Overview — utility tools

absurd params return shipment payment string

Related Articles