使用ZIO-Streams的Redis Stream消費者和生產者實現原始碼
一個利用zio-streams和Redisson庫來使用和產生事件到Redis流的示例應用程式,基於Java 11,使用ZIO-Streams的Redis Stream消費者和生產者實現。點選標題見Github。
ZIO/ZIO Streams庫在Scala函數語言程式設計世界中非常令人著迷,Monad風格。與Akka流相比,ZIO流更簡單,更靈活且更具表現力。
以下是ZIO另外一個使用案例
要求:
- 使用流逐行處理日誌
- 過濾掉不是ERROR或WARN的訊息
- 將流分成2個流:一個用於ERROR,另一個用於WARN訊息
- 根據一定的時間表處理錯誤訊息,例如 每2秒
- 批量處理WARN訊息。例如,將10條訊息分成一批
ZStream是ZIO Streams中的主要構造。首先,我們將從檔案輸入流建立ZStream:
ZStream.fromInputStream(fileInputStream) |
您得到的是流的塊[T]。您可以將Chunk [T]視為Array [T]的不變版本,但效率更高。
.chunks .aggregate(ZSink.utf8DecodeChunk) .aggregate(ZSink.splitLines) .mapConcatChunk(identity) |
然後,我們將Chunk [String]的流轉換為String的流,並且每個元素都是日誌檔案中的一行訊息。
ZIO Streams具有.tap函式,您可以使用該函式使流中的訊息達到峰值。它是除錯流應用的好工具。
.tap(data => putStrLn(s"> $data")) |
然後我們過濾掉不是ERROR或WARN的訊息:
.filter(isErrorWarning) |
下一行程式碼基於isError謂詞返回true或false ,將當前流分成2個流。數字4是緩衝區大小,因此兩個子流可以以不同的速度執行直至緩衝區大小:
.partition(isError, 4) val errorStream = leftStream .mapM(processError(_)) .schedule(Schedule.fixed(2.second)) |
使用ZIO Schedule每2秒處理一次左流中的每個ERROR訊息。
對於正確流中的WARN訊息,我們將一次將它們分為6條訊息並進行批量處理:
val warningStream = rightStream .aggregate(ZSink.collectAllN[String](10)) .mapM(processWarning(_)) |
如果您更容易理解,您可以認為ZSink是訊息生產者/使用者上下文中的訊息使用者。(並認為ZStream是訊息生成器)。ZSink通常用於ZIO Stream中的聚合功能。
最後,我們將2個流合併為一個並收集所有元素:
errorStream.merge(warningStream).runCollect |
以下是完整程式碼:
import java.nio.file.{Files, Paths} import zio._ import zio.console._ import zio.duration._ import zio.stream._ object LogStreamApp extends App { def isErrorWarning(data: String) = { data.contains("ERROR") || data.contains("WARN") } def isError(data: String): Boolean = { data.contains("ERROR") } def processError(data: String) = { putStrLn(s"process error message: ${data}") *> Task.succeed() } def processWarning(list: List[String]) = { putStrLn(s"process warning messages in batch: ${list.length} => $list") *> Task.succeed() } def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = { val is = Files.newInputStream(Paths.get(ClassLoader.getSystemResource("prod_log.txt").toURI())) val theJob = (for { streams <- ZStream .fromInputStream(is) .chunks .aggregate(ZSink.utf8DecodeChunk) .aggregate(ZSink.splitLines) .mapConcatChunk(identity) .tap(data => putStrLn(s"> $data")) .filter(isErrorWarning) .partition(isError, 4) } yield streams).use { case (leftStream, rightStream) => { val errorStream = leftStream .mapM(processError(_)) .schedule(Schedule.fixed(2.second)) val warningStream = rightStream .aggregate(ZSink.collectAllN[String](10)) .mapM(processWarning(_)) errorStream.merge(warningStream).runCollect } } theJob.fold(_ => 1, _ => 0) } } |
the code at github.
相關文章
- 使用BlockQueue實現生產者和消費者模式BloC模式
- 使用Disruptor實現生產者和消費者模型模型
- Java實現生產者和消費者Java
- java實現生產者消費者問題Java
- 生產者消費者問題-C++程式碼實現C++
- 使用wait()與notifyAll()實現生產者與消費者模式AI模式
- 使用Python佇列和多執行緒實現生產者消費者Python佇列執行緒
- ActiveMQ 生產者和消費者demoMQ
- 生產者消費者
- 「Kafka應用」PHP實現生產者與消費者KafkaPHP
- 生產者消費者模式模式
- 生產者消費者模型模型
- 生產者消費者模式,以及基於BlockingQueue的快速實現模式BloC
- C++ condition_variable 實現生產者消費者模型C++模型
- 阻塞佇列和生產者-消費者模式佇列模式
- python 生產者消費者模式Python模式
- 生產消費者模式模式
- python多執行緒+生產者和消費者模型+queue使用Python執行緒模型
- python 多執行緒實現生產者與消費者模型Python執行緒模型
- 鎖,threading local,以及生產者和消費者模型thread模型
- 九、生產者與消費者模式模式
- 生產者與消費者問題
- 多生產者-消費者中假死現象的處理
- 插曲:Kafka的生產者案例和消費者原理解析Kafka
- 分享一個生產者-消費者的真實場景
- 多執行緒併發如何高效實現生產者/消費者?執行緒
- 使用slice和條件變數實現一個簡單的多生產者多消費者佇列變數佇列
- 訊號量實現生產者消費者(程式碼邏輯有問題,不適合多個消費者,不常用)
- 生產者與消費者之Android audioAndroid
- linux 生產者與消費者問題Linux
- 新手練習-消費者生產者模型模型
- Qt基於QSemaphore的生產者消費者模型QT模型
- java編寫生產者/消費者模式的程式。Java模式
- 生產消費實現-寫程式碼
- SpringBoot整合Kafka(生產者和消費者都是SpringBoot服務)Spring BootKafka
- 實戰Spring4+ActiveMQ整合實現訊息佇列(生產者+消費者)SpringMQ佇列
- 什麼是阻塞佇列?如何使用阻塞佇列來實現生產者-消費者模型?佇列模型
- 【mq】從零開始實現 mq-01-生產者、消費者啟動MQ