Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Batched Handlers

batchedWorkerConfig workers batchSize handler passes up to batchSize jobs per call. A grouped batch holds one group. An ungrouped batch holds ready jobs.

-- batchedWorkerConfig <workerCount> <batchSize> handler
config <- Worker.batchedWorkerConfig 10 5 batchHandler

batchHandler
  :: NonEmpty (Arb.JobRead ImagePayload)
  -> Worker.BatchCallbacks (ArbS.SimpleDb AppRegistry IO) ImagePayload Score
  -> ArbS.SimpleDb AppRegistry IO ()
batchHandler jobs cbs = do
  -- bulkProcess :: [Arb.JobRead ImagePayload] -> IO [(Arb.JobRead ImagePayload, Score)]
  scored <- liftIO $ bulkProcess (toList jobs)
  -- Bulk-ack the whole batch in one transaction.
  Worker.ackAllWith cbs scored

Each callback commits on its own. withDbTransaction commits a callback with application writes:

batchHandler jobs cbs =
  for_ jobs $ \job -> do
    score <- liftIO $ scoreImage (Arb.payload job)
    Arb.withDbTransaction $ do
      recordCharge (Arb.payload job)
      Worker.ackWith cbs job score

onJobSuccess fires after the callback's transaction or savepoint completes. Inside an outer transaction, this is before the outer commit. Put once-only database effects in the ack's transaction rather than in the success hook.

If an outer transaction rolls back

A settlement callback can return successfully and still have its database changes rolled back by a later failure:

Arb.withDbTransaction $ do
  Worker.ack cbs job   -- succeeds and releases its savepoint
  updateSomethingElse  -- if this throws, the outer transaction rolls back

In this case, let the exception escape the handler. Catching it to log and then rethrow is fine. Do not catch it and continue processing or settling those jobs. PostgreSQL restores the job, but the worker still considers it settled and no longer heartbeats it. Another worker can reclaim it after its lease expires.

This restriction concerns an outer rollback after a callback returned successfully, not every exception thrown by a callback. It also applies to transactions opened directly through the driver. Success hooks already fired at savepoint release are not undone by the rollback and may fire on redelivery. They are not proof that the outer transaction committed.

CallbackEffect
ack, ackAllcomplete, no result
ackWith, ackAllWithcomplete and store the queue result
failRetry, failRetryAfter, failPermanent, cancelBranch, cancelTree, nack, nackAftersee Error Handling
spawninsert children under the job and suspend it. See runtime spawning

hoistBatchCallbacks calls the callbacks from another monad through a monad morphism. It must keep the worker's connection and schema so each callback joins the handler's transaction. arbiter-orville provides orvilleBatchedHandler, which builds that morphism from the worker's own env.

Callback signatures: BatchCallbacks Haddocks.