2016-07-06 142 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操作没有订阅,因此它立即退出。