如何在同一个函数中订阅多个Redis频道?

时间:2016-07-06 15:49:25

标签: haskell redis

运行Redis 3.2.1和最新的Hedis库,我有以下发布程序:

{-# 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:          example@example.com
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陷阱吗?

3 个答案:

答案 0 :(得分:2)

您需要在一个操作中订阅这两个频道。

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

Hedis没有接到你对pubSub的第二次电话。您可以从pubSub's definition看到除非订阅计数和待处理消息都被耗尽,否则该函数将不会返回。另请注意,没有分叉或其他启用并发的方法。

答案 1 :(得分:1)

build/outputs/aar操作阻止,直到其操作删除所有订阅。

您可以通过查看hedis测试套件中的pubSub测试来了解其工作原理:

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

测试中发生的一切:

  • 分叉线程以分开一秒发送两个事件 - 首先是pubSub事件,然后是chan1事件
  • 第一个chan2pubSub个事件建立了一个监听器。
  • 收到chan1事件后,会将其订阅更改为模式订阅。
  • chan1事件到达时,它会取消所有订阅。然后&#34;控制&#34;转到下一个pubSub行动。
  • 第二个pubSub操作没有订阅,因此它会立即退出。

答案 2 :(得分:0)

使用模式订阅http://redis.io/commands/psubscribe

psubscribe chan*

希望这有帮助