Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/msolli/proletarian/llms.txt

Use this file to discover all available pages before exploring further.

In production, queue workers need to start when your application boots and stop cleanly when it shuts down. Rather than managing this with bare defs, you should integrate Proletarian into whichever component lifecycle library your application already uses. The three patterns below cover the most common Clojure component libraries. All of them follow the same idea: worker/start! in the start/init phase, worker/stop! in the stop/halt phase.
When using a component library, set :proletarian/install-jvm-shutdown-hook? to false (the default). The component library controls application lifecycle — having Proletarian install its own JVM shutdown hook alongside the library’s hooks can lead to double-stop races. Let the library call stop!.
Stuart Sierra’s Component uses a Lifecycle protocol with start and stop methods.
(ns your-app.workers
  (:require [com.stuartsierra.component :as component]
            [proletarian.worker :as worker]
            [next.jdbc :as jdbc]))

(defrecord QueueWorkerComponent [data-source handler-fn queue-worker]
  component/Lifecycle
  (start [this]
    (let [qw (worker/create-queue-worker data-source handler-fn
               {:proletarian/install-jvm-shutdown-hook? false})]
      (worker/start! qw)
      (assoc this :queue-worker qw)))
  (stop [this]
    (when queue-worker
      (worker/stop! queue-worker))
    (assoc this :queue-worker nil)))

(defn new-queue-worker-component [handler-fn]
  (map->QueueWorkerComponent {:handler-fn handler-fn}))
Wire it into your system map and declare a dependency on the component that provides data-source:
(defn new-system []
  (component/system-map
    :db       (new-database-component)
    :worker   (component/using
                (new-queue-worker-component handlers/handle-job!)
                {:data-source :db})))

Accessing system state in handlers

Job handlers often need access to stateful resources — database connections, HTTP clients, caches — that live in your component system. There are two idiomatic patterns for making system state available inside a handler.

Closing over the system map

Construct your handler function inside start/init and close over the system components you need:
(defn make-handler [system]
  (fn [job-type payload]
    ;; All components from your system are in scope here
    (case job-type
      ::send-email  (email/send! (:mailer system) payload)
      ::index-doc   (search/index! (:search-client system) payload)
      ::notify-user (db/write! (:db system) payload))))
Pass make-handler the assembled system in your component’s start method:
;; Component example
(start [this]
  (let [handler (make-handler this)   ;; `this` IS the system map in Component
        qw (worker/create-queue-worker (:data-source this) handler)]
    (worker/start! qw)
    (assoc this :queue-worker qw)))

Using partial for simpler cases

When a handler only needs one or two dependencies, partial keeps things concise:
(defn handle-job! [db mailer job-type payload]
  (case job-type
    ::send-email  (email/send! mailer payload)
    ::write-audit (db/insert! db :audit payload)))

;; In your component start:
(let [handler (partial handle-job! (:db system) (:mailer system))]
  (worker/create-queue-worker ds handler))
Both patterns avoid global state and keep your handlers straightforward to test: call make-handler (or partial) with stub dependencies and invoke the returned function directly.

Build docs developers (and LLMs) love