{"action":"created","issue":{"url":"https://api.github.com/repos/informatikr/hedis/issues/49","repository_url":"https://api.github.com/repos/informatikr/hedis","labels_url":"https://api.github.com/repos/informatikr/hedis/issues/49/labels{/name}","comments_url":"https://api.github.com/repos/informatikr/hedis/issues/49/comments","events_url":"https://api.github.com/repos/informatikr/hedis/issues/49/events","html_url":"https://github.com/informatikr/hedis/issues/49","id":136515209,"number":49,"title":"PubSub: do not depend on messages arriving in order to get control","user":{"login":"Nicowcow","id":6930756,"avatar_url":"https://avatars.githubusercontent.com/u/6930756?v=3","gravatar_id":"","url":"https://api.github.com/users/Nicowcow","html_url":"https://github.com/Nicowcow","followers_url":"https://api.github.com/users/Nicowcow/followers","following_url":"https://api.github.com/users/Nicowcow/following{/other_user}","gists_url":"https://api.github.com/users/Nicowcow/gists{/gist_id}","starred_url":"https://api.github.com/users/Nicowcow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Nicowcow/subscriptions","organizations_url":"https://api.github.com/users/Nicowcow/orgs","repos_url":"https://api.github.com/users/Nicowcow/repos","events_url":"https://api.github.com/users/Nicowcow/events{/privacy}","received_events_url":"https://api.github.com/users/Nicowcow/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-02-25T21:17:39Z","updated_at":"2016-03-18T10:20:28Z","closed_at":null,"body":"Hedis' PubSub interface is really neat, making sure you can never exit without having unsubscribed to all the channels. Unfortunately (unless I missed something) you can never gain control unless a message arrives. A situation is the following: you subscribe to a channel, exchange with redis, and at some point want to unsubscribe; unfortunately you have to wait until the next message arrives in order for your code to be executed. This is clear from the type signature:\r\n\r\n``` haskell\r\npubSub\r\n    :: PubSub                 -- ^ Initial subscriptions.\r\n    -> (Message -> IO PubSub) -- ^ Callback function.\r\n    -> Core.Redis ()\r\n```\r\n\r\nYou could prevent your callback from returning, but it's not particularly elegant, and you'd miss all the further incoming messages (really not an option).\r\n\r\nThe interface is actually really nice, but I think it could somehow be made more powerful. It's annoying to have to use \"bare metal\" commands from `Core` with in order to gain more flexibility. I don't have a solution for this, but it's probably worth thinking about. `pubSub` could look more like `runRedis`, except that it will lock you in if you are still subscribed to any channel, and will prevent you from running any non-pubsub command. \r\n\r\nThat is, there could be a `PubSub` monad (just a newtype wrapper `Redis` just allowing subscription/unsubscription) and `pubSub` would have type \r\n\r\n``` haskell\r\npubSub \r\n    :: [Channel] -- ^ inital subscriptions\r\n    -> PubSub a -- ^ action to run\r\n    -> Either (PubSub a) (Core.Redis a)\r\n```\r\nso that in case you are not fully unsubscribed when returning (that is, if the result of the last command did not return a null number of subscriptions), it would return a `Left (PubSub a)` which you'll have to handle explicitly. This should also help with #28 since all requests can be handled explicitly before `pubSub` returns.\r\n\r\nThis is not as nice as the monoid interface, and probably not the best alternative, but I think it would work. Please let me know if I missed something very simple, and please share your thoughts in general. :)\r\n"},"comment":{"url":"https://api.github.com/repos/informatikr/hedis/issues/comments/198294966","html_url":"https://github.com/informatikr/hedis/issues/49#issuecomment-198294966","issue_url":"https://api.github.com/repos/informatikr/hedis/issues/49","id":198294966,"user":{"login":"Nicowcow","id":6930756,"avatar_url":"https://avatars.githubusercontent.com/u/6930756?v=3","gravatar_id":"","url":"https://api.github.com/users/Nicowcow","html_url":"https://github.com/Nicowcow","followers_url":"https://api.github.com/users/Nicowcow/followers","following_url":"https://api.github.com/users/Nicowcow/following{/other_user}","gists_url":"https://api.github.com/users/Nicowcow/gists{/gist_id}","starred_url":"https://api.github.com/users/Nicowcow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Nicowcow/subscriptions","organizations_url":"https://api.github.com/users/Nicowcow/orgs","repos_url":"https://api.github.com/users/Nicowcow/repos","events_url":"https://api.github.com/users/Nicowcow/events{/privacy}","received_events_url":"https://api.github.com/users/Nicowcow/received_events","type":"User","site_admin":false},"created_at":"2016-03-18T10:20:28Z","updated_at":"2016-03-18T10:20:28Z","body":"@k-bx I fear more and more that I have been missing something about the `PubSub` API. My use case is the following:\r\n\r\n`A` publishes on two channels, `foo` and `bar`. To start with, `B` is only subscribed to `foo`. `B` receives all the `foo` messages from `A`, and everything is fine. After a while, `A` stops publishing on `foo`, and publishes only on `bar`. `B` would now like to subscribe to `bar`. How can `B` do that? What I understood from the current API is that `B` cannot subscribe to `bar` (at least not in the same thread) nor unsubscribe from `foo` (without a thread kill) until any message arrives on `foo`. This reason is that the pub sub API is purely callback-based, i.e. you can never take any action *unless* you have received a message. Am I missing something?"}}