2016-07-06 41 views
1

運行Redis的3.2.1和最新HEDIS庫,我有以下出版商計劃:如何在同一功能中訂閱多個Redis頻道?

{-# LANGUAGE OverloadedStrings #-} 
module Main where 

import Database.Redis 
import Control.Monad 
import Control.Concurrent 
import Control.Monad.Trans 
import Data.ByteString as BS 
import System.Posix.Process 
import Data.String.Conv 

main :: IO() 
main = do 
    conn <- connect defaultConnectInfo 
    runRedis conn run 

run = do 
    liftIO $ threadDelay $ 1000 * 1000 
    pid <- liftIO getProcessID 
    publish "chan1" (toS $ show pid) 
    publish "chan2" (toS $ show pid) 
    liftIO $ Prelude.putStrLn "\n\n%%%%%%%\n\nnext\n\n%%%%%%%%\n\n" 
    run 

的用戶看起來是這樣的:

{-# LANGUAGE OverloadedStrings #-} 
module Main where 

import Database.Redis 

main :: IO() 
main = do 
    conn <- connect defaultConnectInfo 
    runRedis conn $ do 
    pubSub (subscribe ["chan1"]) $ \msg -> do 
     putStrLn $ "chan1 " ++ show (msgChannel msg) ++ ": " ++ show (msgMessage msg) 
     return mempty 
    pubSub (subscribe ["chan2"]) $ \msg -> do 
     putStrLn $ "chan2" ++ show (msgChannel msg) ++ ": " ++ show (msgMessage msg) 
     return mempty 

輸出是:

%%%%%%% 

next 

%%%%%%%% 

chan1 "chan1": "21542" 

%%%%%%% 

next 

%%%%%%%% 

chan1 "chan1": "21542" 

%%%%%%% 

next 

%%%%%%%% 

chan1 "chan1": "21542" 

%%%%%%% 

next 

%%%%%%%% 

現在看來,只要用戶讀取第一個通道,就不會讀取發送到第二個通道的消息。換句話說,看起來簡單地忽略了訂閱chan2的命令。

爲了完整起見,這裏是我的Cabal文件:

name:    pub-sub-exp 
version:    0.1.0.0 
synopsis:   Simple project template from stack 
description:   Please see README.md 
homepage:   https://github.com/githubuser/pub-sub-exp#readme 
license:    BSD3 
license-file:  LICENSE 
author:    Author name here 
maintainer:   [email protected] 
copyright:   2016 Author name here 
category:   Web 
build-type:   Simple 
cabal-version:  >=1.10 

executable pub 
    hs-source-dirs:  src 
    main-is:    Pub.hs 
    default-language: Haskell2010 
    build-depends:  base >= 4.7 && < 5, 
         hedis, 
         mtl, 
         bytestring, 
         unix, 
         string-conv 

executable sub 
    hs-source-dirs:  src 
    main-is:    Sub.hs 
    default-language: Haskell2010 
    build-depends:  base >= 4.7 && < 5, 
         hedis, 
         mtl, 
         bytestring 

我使用stack-lts-6.6


爲了清楚起見,我想訂戶,以指示消息被髮送到兩個信道1和2

這是Redis的的公知的特性?我是否錯過了一些Haskell的疑難雜症?

回答

2

您需要申請兩個通道在一個單一的動作。

pubSub (subscribe ["chan1", "chan2"]) $ \msg -> do 

Hedis沒有到達您的第二個電話pubSub。您可以從pubSub's definition中看到,除非訂閱計數和待處理消息都耗盡,否則該函數將不會返回。另請注意,沒有分叉或其他方法來啓用併發。

+0

嗯...所以這是'hedis'實現的一個未記錄的特徵?或者它是從'redis'繼承的東西? – Zyxoas

+1

有點A列,有點B列。它實際上有文檔記錄(只是不在'pubSub'函數本身中),並且是給定Redis的PubSub語義的有意行爲。查看[Hackage上的''hedis'包](http://hackage.haskell.org/package/hedis)的描述中的** Enforced Pub/Sub語義**部分。 –

+0

雖然@ ErikR的答案是正確的 - 因爲它解釋了使用源代碼爲什麼這種行爲是如此 - 這個答案實際上解釋了更高級別的行爲,並給出了代碼片段以獲得期望的結果。所以我會接受這個。 謝謝。 – Zyxoas

1

pubSub操作將阻止,直到其操作移除所有預訂。

你可以看到這是如何工作通過看在HEDIS測試套件PubSub的測試:

https://github.com/informatikr/hedis/blob/e86143db2d4e76fe85340c78c01da7bc3722ae5a/test/Test.hs#L385

什麼測試那張跟蹤:

  • 線程是分叉發送兩個事件相隔一秒 - 首先是chan1事件,然後是chan2事件
  • 第一個pubSub建立了一個監聽器chan1事件。
  • 當它收到chan1事件時,它將其訂閱更改爲模式訂閱。
  • chan2事件到達時,它取消所有訂閱。然後「控制」轉到下一個pubSub操作。
  • 第二個pubSub操作沒有訂閱,因此它立即退出。