Skip to content

Basic bindings to the recently implemented pgo_notifications. - #78

Open
foxfriends wants to merge 2 commits into
lpil:mainfrom
foxfriends:main
Open

Basic bindings to the recently implemented pgo_notifications.#78
foxfriends wants to merge 2 commits into
lpil:mainfrom
foxfriends:main

Conversation

@foxfriends

@foxfriends foxfriends commented Dec 29, 2025

Copy link
Copy Markdown

Added support for PostgreSQL LISTEN/NOTIFY by lightly wrapping the implementation in pgo.

As in pgo:

  • The notifications listener is started as a new process, different from a regular connection.
  • The listen(conn, channel) function subscribes to a Postgres channel.
  • unlisten(conn, reference) can be used to unsubscribe.
  • Notifications from Postgres are sent to the process that called listen as the Notify type. Receive these using the pog.notification_selector().

General usage example:

let assert Ok(db) = pog.default_config("db")
    |> pog.start()

let assert Ok(notifications) = pog.default_config("notifications")
    |> pog.start_notifications()

let assert Ok(reference) = pog.listen(notifications.data, "some_channel")

let selector = pog.notification_selector()

let assert Ok(_) = pog.query("NOTIFY some_channel, 'some_payload'")
    |> pog.execute(db.data)

let assert Ok(Notify(pid, ref, chan, data)) = process.selector_receive(selector, 100)
assert pid == notifications.pid
assert ref == reference
assert chan == "some_channel"
assert data = "some_payload"

pog.unlisten(notifications.data, reference)

Closes #13

@foxfriends
foxfriends force-pushed the main branch 3 times, most recently from 4184091 to dae5cc3 Compare December 31, 2025 19:05
Added support for PostgreSQL `LISTEN/NOTIFY` by lightly wrapping the
implementation in `pgo`.

As in `pgo`:
* The notifications listener is started as a new process, different from a regular connection.
* The `listen(conn, channel)` function subscribes to a Postgres channel.
* `unlisten(conn, reference)` can be used to unsubscribe.
* Notifications from Postgres are sent to the process that called `listen` as the `Notify` type. Receive these using the `pog.notification_selector()`.

General usage example:

```gleam
let assert Ok(db) = pog.default_config("db")
    |> pog.start()

let assert Ok(notifications) = pog.default_config("notifications")
    |> pog.start_notifications()

let assert Ok(reference) = pog.listen(notifications.data, "some_channel")

let selector = pog.notification_selector()

let assert Ok(_) = pog.query("NOTIFY some_channel, 'some_payload'")
    |> pog.execute(db.data)

let assert Ok(Notify(pid, ref, chan, data)) = process.selector_receive(selector, 100)
assert pid == notifications.pid
assert ref == reference
assert chan == "some_channel"
assert data = "some_payload"

pog.unlisten(notifications.data, reference)
```
@foxfriends

Copy link
Copy Markdown
Author

erleans/pgo#119

I found and patched a bug in the underlying pgo implementation, so I suggest waiting until that's merged before considering accepting this PR.

Having been trying out my patch for a few days in a project, I am finding it to work fine, but maybe is not the most idiomatic Gleam; pretty new to it all, and not sure the best way to represent this system, I went with a "light" approach so far, mimicking the pgo interface, but open to suggestions to make it more "Gleam" flavoured for sure. :)

@lpil lpil left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I've left some questions inline

Comment thread src/pog.gleam
Comment thread src/pog.gleam
Comment thread src/pog.gleam
Comment thread src/pog.gleam
Comment thread src/pog.gleam Outdated
Comment thread src/pog.gleam Outdated
Comment thread src/pog.gleam
Comment thread src/pog_ffi.erl Outdated
Comment thread src/pog_ffi.erl
@foxfriends

Copy link
Copy Markdown
Author

Thanks for the notes, I have updated it, let me know if anything else :)

@renatillas

renatillas commented Jul 31, 2026

Copy link
Copy Markdown

Hello @foxfriends! While integrating notification sessions under supervision, I found two lifecycle edges:

  • pgo_notifications:listen/2 may return {eventually, Ref} during reconnection, while the PR handles only {ok, Ref}

  • and the notification process traps and ignores linked shutdown exits, so supervisor teardown times out unless we call gen_statem:stop(Pid, shutdown, Timeout) directly.

Would it make sense to normalize {eventually, Ref} and expose a graceful notification-session stop API or supervision specification?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LISTEN/NOTIFY support?

3 participants