Open albertov opened 6 years ago
Not currently. It looks like should be fairly easy to add a simple call to check/wait for a notification, though.
It would be more tricky to make this thread-safe (so that you could issue a query on the same connection while waiting for a notification), but that's mostly because nothing is thread safe currently.
If the simple version is sufficient, I'm happy to take a pass. Let me know if you have any thoughts on a better interface (like, registering a callback for a notify somehow?).
The simple version is enough for my case. I'm dedicating a connection exclusively to a single thread that listens to notifies so I don't foresee any thread-safety issues. Besides my case, I believe no ever driver I've ever seen allows a connection to be used among multiple threads safely (unless it is pooled or mutexed) so the simple version would be on par feature-wise anyway.
Regarding a higher-level interface, I'm currently exposing the notification services to the rest of the app in a (~100 loc) module with an interface that looks like this:
type Notification = ByteString
type Topic = ByteString
type TopicChan = (Int, BroadcastChan In Notification)
type Topics = M.HashMap Topic TopicChan
data Dispatcher = Dispatcher Connection (MVar Topics)
newtype Outlet = Outlet (BroadcastChan Out Notification)
-- | Starts a thread to wait for Notifications. A connection is created for this thread.
-- Both the connection and thread are closed/killed after exiting this function
withDispatcher
:: (MonadLoggerIO m, MonadBaseControl IO m)
=> DBConfig -> (Dispatcher -> m a) -> m (Either ConnectionError a)
-- | Subscribes to a Topic, use getNotification to wait for Notifications.
-- Subscription is unregistered when exiting this function so don't use the Outlet
-- afterwards
withOutlet
:: (MonadLogger m, MonadBaseControl IO m)
=> Dispatcher -> Topic -> (Outlet -> m a) -> m a
-- | Blocks for a notification
getNotification :: MonadBase IO m => Outlet -> m Notification
-- | Sends a notification. All processes listening on the 'Topic' will receive it
sendNotification
:: MonadBase IO m
=> Dispatcher -> Topic -> Notification -> m ()
I would gladly submit a PR adapting it use postgresql-typed if you're OK with the interface and think it belongs in here.
The only thing it needs from the db driver is to be able to open a connection, execute a LISTEN (to implement withOutlet
, this can be done right now) and receive async NOTIFYs (to implement 'getNotification')
It uses broadcast-chan since it was I was using when experimenting and never got to clean it up but it should work fine with plain STM channels since a channel (ie: Outlet) never has no listeners which could cause the kind of space-leaks broadcast-chan is designed to prevent.
It can also be specialized to IO to follow the style of the rest of the library.
Interesting, I guess that makes sense. I think I'll just start with getNotification
for now, probably quite similar to what postgresql-simple has, and see how that goes.
Great, thanks! I'll keep an eye so I try it out and submit the Notifications module for review.
See if that works for you. Also, feel free to add some extra tests if you have any.
Thinking about the higher level interface, I guess one concern is that I'd rather not add more dependencies to the main library. I'll keep thinking about it, but it might be better as a separate library.
Sorry for the delay... I'll try to migrate this weekend to use this new functionality and let you know how it goes. I think the higher-level interface might be doable without any extra dependencies by specializing it to IO
and uisng Control.Concurrent.Chan
from base
. I'll give it a shot and report back.
Thanks!
Is it possible to use this library to receive asynchronous notifications from the database server? I'm currently using postgresql-simple's Notification just for this functionality as I couldn't find a way to do it with this library but I'd rather avoid the extra dependency if possible.
Thanks for this amazing library BTW, it's been a pleasure to use so far.