Akka流:将新的发布者/订阅者附加到Flow

时间:2018-02-22 22:56:49

标签: scala websocket akka publish-subscribe akka-stream

我正在构建一个Akka应用程序,并希望将某些actor的FSM状态转换暴露给外部消费者。 (最终目标是能够将状态转换消息推送到websocket,以便可以实时查看它们。)

基于文档Combining dynamic stages to build a simple Publish-Subscribe service,看起来我需要公开代表pub-sub通道的Flow,以便消费者和生产者可以使用它。

我遇到问题的部分是将新的源附加到Flow,以便生成的每个新actor将其状态转换发布到Source。另一个问题是向Flow添加新的接收器(最后,这将是websockets,但出于测试目的,它可能是任何新的接收器。)

首先,我连接MergeHub和BroadcastHub以形成"频道"然后从物化接收器和源创建Flow:

Set objShell = CreateObject("WScript.Shell")
Set objFso = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFso.GetFolder(objShell.CurrentDirectory)
Set TifCollection = CreateObject("Scripting.Dictionary")
Set objLines = CreateObject("Scripting.Dictionary")

' Compile 2-dimensional array listing all documents with their pages
For Each objFile In objFolder.Files
  If objFso.GetExtensionName (objFile.Path) = "jpg" Then
    file = Split(objFile.Name, "_")(0)
    page = Split(objFile.Name, "_")(1)
    If Not TifCollection.Exists(file) Then
        TifCollection.Add file, CreateObject("Scripting.Dictionary")
    End If
    TifCollection.Item(file).Add page, ""
  End If
Next

funcSortKeysByLengthDesc(TifCollection)

' Loop through the array to compile the loadfile
For Each file In TifCollection.Keys
  For Each page In TifCollection(file)
    If (page = "1.jpg") Then 
      objLines.Add file & ",," & file & "_" & page & ",Y,,," & TifCollection(file).Count, ""
    Else 
      objLines.Add file & ",," & file & "_" & page & ",,,,", ""
    End If
  Next
Next

' Write to filesystem
strFileName = year(date) & month(date) & day(date) & hour(time) & minute(time) & second(time) & "-" & objLines.Count & "-IMAGES.opt"
Set objLoadfile = objFso.CreateTextFile(objFolder & "\" & strFileName,True)
objLoadfile.Write(Join(objLines.Keys, VBCRLF))



Function funcSortKeysByLengthDesc(dctList As Object) As Object
    'todo
End Function

那么问题是如何动态地将新生产者和消费者添加到此流程?有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我在我的一个项目中使用以下解决方案,以通过多个请求处理器处理来自websocket的请求,这些请求处理器可能产生响应流或提供无穷的订阅。

// requests coming from websocket, it could be any source, it's doesn't matter
val requests: Source[Request, NotUsed] = ... 

// the request processing here can provide endles stream of responses
val requestProcessing: Flow[Request, Response, NotUsed] = ...

val (outSink, outSource) =
  MergeHub
    .source[Result](perProducerBufferSize = 4)
    .toMat(BroadcastHub.sink(bufferSize = 32))(Keep.both)
    .run()

Source.tick(Duration.Zero, KeepAliveInterval, ConnectionKeepAlive)
  .to(outSink)
  .run()

requests.fold {
  case State(state, AuthRequest(r)) if checkAuth(r) => 
    Source.single(AuthenticationAck).to(outSink)
    state.copy(isAuthenticated = true)
 case State(state, AuthRequest(r)) => 
    Source.single(AuthenticationFailedError).to(outSink)
    state

 case State(state, request) if s.isAuthenticated =>
    // here the most of busines
    Source.single(request).via(requestProcessing).to(outSink)
    state

 case State(state, _) => 
    Source.single(NonAuthorizedError).to(outSink)
    state
}.toMat(Sink.ignore)(Keep.right)

outSource.runForeach { response =>
  // here we get the stream of responses mixed from all requests
}

outSource.runForeach { response =>
  // of course, we could have as many subscribers as we need
}

我希望这会有所帮助:)

答案 1 :(得分:0)

对于这个特殊问题,我不会使用akka-stream。您描述的多播pub-sub类型更适合原始Actor消息传递和EventStream

在某些情况下,我是akka-stream的忠实粉丝,但在这种情况下,我认为你正试图通过圆孔安装方形钉。