ihp-1.6.0: Haskell Web Framework
Safe HaskellNone
LanguageGHC2021

IHP.Job.Queue.Watch

Synopsis

Documentation

watchForJob :: (?context :: context, HasField "logger" context FastLogger) => Pool -> PGListener -> Text -> Int -> TBQueue JobWorkerProcessMessage -> ResourceT IO (Subscription, ReleaseKey) Source #

Calls a callback every time something is inserted, updated or deleted in a given database table.

In the background this function creates database triggers and checks that they exist. The triggers notify this function about table changes using pg_notify. If installing the triggers fails temporarily, jobs are still found by the poller and trigger installation is retried.

This function returns a Async. Call cancel on the async to stop watching the database.

Example:

watchInsertOrUpdateTable "projects" do
    putStrLn "Something changed in the projects table"

Now insert something into the projects table. E.g. by running make psql and then running INSERT INTO projects (id, name) VALUES (DEFAULT, 'New project'); You will see that "Something changed in the projects table" is printed onto the screen.

watchForJobWithPollerTriggerRepair :: (?context :: context, HasField "logger" context FastLogger) => Bool -> Pool -> PGListener -> Text -> Int -> TBQueue JobWorkerProcessMessage -> ResourceT IO (Subscription, ReleaseKey) Source #

Like watchForJob but allows disabling the poller-side trigger integrity check.

pollForJob :: (?context :: context, HasField "logger" context FastLogger) => Bool -> Pool -> Text -> Int -> TBQueue JobWorkerProcessMessage -> ResourceT IO ReleaseKey Source #

Periodically checks the queue table for open jobs. Calls the callback if there are any.

watchForJob only catches jobs when something is changed on the table. When a job is scheduled with a runAt in the future, and no other operation is happening on the queue, the database triggers will not run, and so watchForJob cannot pick up the job even when runAt is now in the past.

This function returns a Async. Call cancel on the async to stop polling the database.

ensureNotificationTriggers :: (?context :: context, HasField "logger" context FastLogger) => Pool -> Text -> IO () Source #

createNotificationTriggerSQL :: ByteString -> Text Source #

Returns a SQL script to create the notification trigger.

The function body is always updated via CREATE OR REPLACE FUNCTION, which only locks the function's row in pg_proc, not the job table.

The trigger DDL is only executed when a trigger is missing: DROP TRIGGER takes an AccessExclusiveLock on the job table, which conflicts with every other lock — even the AccessShareLocks held by a running pg_dump. Running DROP + CREATE TRIGGER unconditionally on every start meant a job worker (re)started while a backup was in flight would block on the trigger DDL, and all subsequent INSERTs/UPDATEs on the job table would queue up behind that pending lock request, stalling job processing until the backup finished.

When a trigger is missing (first install or after make db), the table lock required by CREATE TRIGGER is acquired with NOWAIT. This prevents the repair from queuing behind an active writer and then blocking later writes. The caller falls back to the poller and retries later. Healthy triggers are never dropped.

The non-blocking advisory lock ensures only one process attempts installation at a time. Other processes immediately fall back to polling instead of queuing behind it. Changes to an existing trigger definition require an explicit migration because worker startup deliberately never drops a healthy, existing trigger.

channelName :: ByteString -> ByteString Source #

Retuns the event name of the event that the pg notify trigger dispatches