{"id":13989194,"url":"https://github.com/danielshaya/reactivejournal","last_synced_at":"2025-07-22T10:31:39.854Z","repository":{"id":77725672,"uuid":"90792682","full_name":"danielshaya/reactivejournal","owner":"danielshaya","description":"ReactiveJournal a journalling facility for Reactive Streams. Intended for testing, remote connections and effective handling of back pressure","archived":false,"fork":false,"pushed_at":"2017-07-05T12:05:14.000Z","size":500,"stargazers_count":27,"open_issues_count":1,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-11-29T08:38:18.638Z","etag":null,"topics":["chronicle","java","journal","memory-mapped","rxjava"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danielshaya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"License.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-05-09T21:16:13.000Z","updated_at":"2020-10-13T21:40:47.000Z","dependencies_parsed_at":"2023-03-01T14:46:10.265Z","dependency_job_id":null,"html_url":"https://github.com/danielshaya/reactivejournal","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/danielshaya/reactivejournal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielshaya%2Freactivejournal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielshaya%2Freactivejournal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielshaya%2Freactivejournal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielshaya%2Freactivejournal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielshaya","download_url":"https://codeload.github.com/danielshaya/reactivejournal/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielshaya%2Freactivejournal/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266475120,"owners_count":23934885,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chronicle","java","journal","memory-mapped","rxjava"],"created_at":"2024-08-09T13:01:33.332Z","updated_at":"2025-07-22T10:31:34.811Z","avatar_url":"https://github.com/danielshaya.png","language":"Java","funding_links":[],"categories":["Java"],"sub_categories":[],"readme":"# ReactiveJournal\n\nReactiveJournal supports [Reactive](http://www.reactive-streams.org/) libraries by adding \nfunctionality to record and replay reactive streams. \n\n## Downloading the project\n\n### Maven\nReactiveJournal is a Maven project so you can `git clone` the project and build in the usual way.\n\nThe intention is for this project to make its way into Maven Central (work in progress).\n\n### Download the jar\nGo to the releases section of the project. With each release there will be an uber jar that you \ncan download with the ReactiveJournal classes and all dependencies.\n\nOnce downloaded you can test that it works by running:\n\n````\njava -cp ./reactivejournal-x.x.x.jar org.reactivejournal.examples.helloworld.HelloWorld \n````\n## Why ReactiveJournal??\n\nPicture this scenario...\n\nYou've just released your shiny new Reactive project. Streams of data start to flow into the system,\nyour 'Reactives' are busy processing the data, enriching it, making decisions based on it, creating\nnew streams of data for Reactives further down the line to consume. It's the well oiled engine of\nan F1 car, a\nthing of beauty, poetry in motion. Exactly what a Reactive system was designed to do.\n\nBut then...\n\nSomething starts going wrong. Perhaps data received isn't quite as clean as it should be, \nthe system gets dirty, components clog up and fail, data backs up. Processes slow down,\nbefore long we have total melt down. Our F1 engine is a heap a smouldering metal.\n\nBut what went wrong... this is what we need to be able to our system:\n\n* Recreate the exact situation so that can step through it and understand\nwhere the root of the problem is.\n\n* Capture that scenario fix it and include it in a test case so that it never \nhappens again.\n\n* Monitor the slowdown of the system by observing the queues build up. Recover\nthe system without losing any data in the meantime.\n\n* Deal with the surge in data that caused the component to start runing\nout of memory. \n\n* Run multiple processes to process our data rather than relying on the one\nwhich went over.\n\n* All the above without slowing the system down or having to do any development.\n\nJournaling addresses all these points. ReactiveJournal was designed to makes journaling for \nReactive programs as simple as it could possible be.\n \n\n## Primary Motivations Behind ReactiveJournal\n\n### 1. Testing\n\nTesting is a primary motivation for ReactiveJournal. ReactiveJournal allows developers to\nblack box test their code by recording all inputs and outputs in and out of their programs.\n\nAn obvious use case are unit tests where ReactiveJournal recordings can be used to create\ncomprehensive tests (see [HelloWorldTest](https://github.com/danielshaya/reactivejournal/blob/master/src/main/java/org/reactivejournal/examples/helloworld/HelloWorldTest.java) for an example). This example makes use of\n`ReactiveValidator` which allows unit tests to compare their results against previously\nrecorded results in the journal.\n\nAnother powerful use case is to enable users to replay production data into test systems. \nBy simply copying over the journal file from a production system and replaying \nall or part of the file\ninto a test system the exact conditions of the primary system will be reproduced.\n\n### 2. Remote Connections\n\nReactiveJournal can be recorded on one JVM and can be replayed (in real-time if required) \non one or more \nJVMs provided they have access to the journal file location.  \n\nThe remote connection can either read from the beginning of the recording or just start with live \nupdates from the recorder. The remote connection (the 'listener') can optionally write back to the \njournal effecting a two way conversation or RPC. There can be multiple readers and writers to the\njournal.\n\nReactiveJournal uses [Chronicle-Queue](https://github.com/OpenHFT/Chronicle-Queue/blob/master/README.adoc) (a memory mapped file solution) \nserialisation meaning that\nthe process of moving data from one JVM to another is exceedingly efficient and can be achieved \nin single digit micro seconds. \n\nIf you need to pass data between JVMs on the same machine this is not only the most efficient way \nto do so but you will also provide you with a full recording of the data that is \ntransferred between the JVMs.\n\nSetting up remote listeners allows a system to have live (hot) backup processes.  Another\npowerful strategy is to set\nup processes running different code bases so that you can live test new code or play with \nalternative algorithms and compare results with the exisiting sytem.\n\n### 3. Slow consumers (handling back pressure)\n\nIf you have a fast producer that you can't slow down but your consumer can't keep up\nthere are a few options available to your system.\n\nMost often you end up implementing strategies that hold buffers of data in memory allowing the\nconsumer to catch up eventually. The problem with those sort of strategies are one, if your process\ncrashes you lose all the data in your buffer. Therefore if you need to consume the fast data in a \ntransactional manner this will not be an option. Two, you may run out of memory if the \nbuffers get really big. At the very least you will probably need to run your JVM with a large\nmemory setting that many be inefficient. For latency sensitive applications it will \nput pressure on the GC which will not be acceptable.\n\nIn such scenarios you can publish your data to ReactiveJournal which shouldn't have any problems\nkeeping up with most feeds (typically writing in the order of 1,000,000/s). You can then read\nyour data from ReactiveJournal knowing that the data is safely stored on disk without having to\nkeep any data in memory buffers.\n\nSee more about this topic below in the [Examples](https://github.com/danielshaya/reactivejournal/tree/master/src/main/java/org/reactivejournal/examples) section\n\n## Design Goals\n\n- Recording to the journal is transactional i.e. no data will be lost if the \nprogram crashes\n- Recording and playback is so fast that it won't slow down the host program.\n- Recording and playback can be achieved without any gc overhead\n- RxRecorder can be easily added (or even retro-fitted) into any `Reactive` project\n\n# Quick Start\n## Creating a Journal\n\nAn `ReactiveJournal` is created as follows:\n\n    ReactiveJournal reactiveJournal = new ReactiveJournal(String dir);\n\nThe directory is the location where the serialised file will be created \n\n## Recording a reactive stream\n`ReactiveRecorder` allows any Reactive [`Publisher`](https://github.com/reactive-streams/reactive-streams-jvm/blob/master/api/src/main/java/org/reactivestreams/Publisher.java) to be journaled to disk using \nthe `record` function:\n    \n    ReactiveRecorder reactiveRecorder = reactiveJournal.createReactiveRecorder();\n    reactiveRexcorder.record(Publisher)\n\nFor notes on threading see FAQ below.\n\n## Playing back a reactive stream\n\n`ReactivePlayer` is used to playback the journal recording:\n\n    ReactivePlayer reactivePlayer = reactiveJournal.createReactivePlayer();\n    Publisher = reactivePlayer.play(new PlayOptions());\n    \nThere are a number of options that can be configured using `PlayOptions`. These\ninclude filtering the stream by time and stream. Playback speed can also be\ncontrolled using this configuration.\n\n## Viewing the contents of a journal\n\n`ReactiveJournal` is created and stored to disk using the low latency Chronicle-Queue library.\nThe data can be examined in plain ASCII using the writeToDisk function:\n\n    reactiveJournal.writeToDisk(String fileName, boolean printToSdout)\n\n## Putting it together with HelloWorld\n\nFull code example code [HelloWorldApp](https://github.com/danielshaya/ReactiveJournal/blob/master/src/main/java/org/ReactiveJournal/examples/helloworld/HelloWorld.java).\n\n```java\npackage org.reactivejournal.examples.helloworld;\n\nimport org.reactivejournal.impl.PlayOptions;\nimport org.reactivejournal.impl.ReactiveJournal;\nimport org.reactivejournal.impl.ReactiveRecorder;\nimport org.reactivestreams.Publisher;\nimport org.reactivestreams.Subscriber;\nimport org.reactivestreams.Subscription;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * Simple Demo Program\n */\npublic class HelloWorld {\n    private static final String tmpDir = System.getProperty(\"java.io.tmpdir\");\n\n    public static void main(String[] args) throws IOException {\n        //1. Create the reactiveRecorder and delete any previous content by clearing the cache\n        ReactiveJournal reactiveJournal = new ReactiveJournal(tmpDir + File.separator + \"HW\");\n        reactiveJournal.clearCache();\n\n        //2. Create a HelloWorld Publisher\n        Publisher\u003cString\u003e helloWorldFlowable = subscriber -\u003e {\n            subscriber.onNext(\"Hello World!\");\n            subscriber.onComplete();\n        };\n\n        //3. Pass the Publisher into the reactiveRecorder which will subscribe to it and record all events.\n        ReactiveRecorder reactiveRecorder = reactiveJournal.createReactiveRecorder();\n        reactiveRecorder.record(helloWorldFlowable, \"\");\n\n        //4. Subscribe to ReactiveJournal and print out results\n        Publisher recordedObservable = reactiveJournal.createReactivePlayer().play(new PlayOptions());\n\n        recordedObservable.subscribe(new Subscriber() {\n            @Override\n            public void onSubscribe(Subscription subscription) {\n                subscription.request(Long.MAX_VALUE);\n            }\n\n            @Override\n            public void onNext(Object o) {\n                System.out.println(o);\n            }\n\n            @Override\n            public void onError(Throwable throwable) {\n                System.err.println(throwable);\n            }\n\n            @Override\n            public void onComplete() {\n                System.out.println(\"Hello World Complete\");\n            }\n        });\n\n        //5. Sometimes useful to see the recording written to a file\n        reactiveJournal.writeToFile(tmpDir + File.separator + \"/hw.txt\",true);\n    }\n}\n```    \nThe results of running this program can be seen below:\n\n````\n[main] INFO org.reactivejournal.impl.ReactiveJournal - Deleting existing recording [/tmp/HW/.reactiveJournal]\nHello World!\n[main] INFO org.reactivejournal.impl.ReactiveJournal - Writing recording to dir [/tmp//hw.txt]\nHello World Complete\n[main] INFO org.reactivejournal.impl.ReactiveJournal - VALID\t1\t1499202194782\t\tHello World!\n[main] INFO org.reactivejournal.impl.ReactiveJournal - COMPLETE\t2\t1499202194784\t\tEndOfStream{}\n[main] INFO org.reactivejournal.impl.ReactiveJournal - Writing to dir complete\n````\n\n## PlayOptions\n\nWhen playing back from ReactiveJournal there are a number of options that can be set summarised in the table below:\nThey are explained more fully in the FAQ and in the [javadoc](https://github.com/danielshaya/reactivejournal/blob/master/src/main/java/org/reactivejournal/impl/PlayOptions.java) for `PlayOptions`\n\n| Option Name   | Values           | Default       | Description  |\n| ------------- |------------------| ------------- | -------------|\n| filter        | any string       | n/a           | All messages are written with a filter tag |\n| pauseStrategy | SPIN / YIELD     | YIELD         | Determines the pause strategy if no events in the journal |\n| playFromNow   | true / false     | false         | Only play message from now - ignore older messages |\n| playFromSeqNo | any long         | Long.MIN_VALUE| Only play messages from seqNo |\n| playUntilSeqNo| any long         | Long.MAX_VALUE| Only play messages until seqNo and then complete |\n| playFromTime  | any long         | Long.MIN_VALUE| Only play messages from time in millis |\n| playUntilTime | any long         | Long.MAX_VALUE| Only play messages until time in millis and then complete |\n| replayRate    | FAST / ACTUAL_TIME | FAST        | Play back messages fast or with the intervals they were recorded |\n| sameThread    | true / false     | false         | Play back messages on the subscriber thread or a new one |\n| using         | any Object       | null          | Use this Object to populate the message - save on GC |\n\n\n## FAQ\n\n### What types of data can be serialised by ReactiveJournal\n\nItems that can be serialised to ReactiveJournal are those that can be serialised to \nChronicle-Queue.\n\nThese are:\n* AutoBoxed primitives, Strings and byte[]\n* Classes implementing `Serialisable`\n* Classes implementing `Externalizable`\n* Classes implementing `Marshallable`\n\nSee [Chronicle Queue Docs](https://github.com/OpenHFT/Chronicle-Queue#restrictions-on-topics-and-messages) for full documentation\n\n### How to use in conjunction with Reactive implementations such as RxJava and React?\n\n`ReactiveJava` has been designed be used with any [Reactive](https://github.com/reactive-streams) implentation \nsuch as [RxJava](https://github.com/ReactiveX/RxJava) and [Reactor](https://projectreactor.io/).\n\nFor example if you had an RxJava `Flowable`, because `Flowable` implements `Publisher`, \nyou could use the `Flowable` as input to \n`ReactiveRecorder.record()` which takes a `Publisher`. ()If you have an RxJava\n`Observable` you would have to convert it to a `Flowable` with `Observable.toFlowable()`\nfirst.)\n\n`ReactivePlayer` returns a `Publisher` that can be converted to `Flowable` with\n `Flowable.fromPublisher(reactivePlayer.play(options))`. There is utility class\n `RxPlayer` that does this for the RxJava user. \n\n\n### ReactiveJournal on the critical path or as another subscriber \n \nThere are 2 ways you might want to set up your `ReactiveJournal`.\n\n1. Record your `Publisher` input into `ReactiveJournal` and then subscribe to\n`ReactiveJournal` for its stream of events. This effectively inserts `ReactiveJournal` \ninto the critical path of\nyour program. This will certainly be the setup if you are using ReactiveJournal \nto handle back pressure.\nThis is demonstrated in the example program [HelloWorldApp_JournalPlayThrough](https://github.com/danielshaya/reactivejournal/blob/master/src/main/java/org/reactivejournal/examples/helloworld/HelloWorldApp_JournalPlayThrough.java)\n\n2. Have `ReactiveJournal` as a second subscriber to your `Publisher`. This has the benefit\nof keeping all functions on the same thread. This might be the setup if you are using `ReactiveJournal`\nto record data for testing purposes. If you are using RxJava you might want to use \nthe `ConnectableObservable` paradigm\nas you won't want ReactiveRecorder kicking off the connection until\nall the other connections have been setup. \nThis is demonstrated in the example program [HelloWorldApp_JounalAsObserver](https://github.com/danielshaya/reactivejournal/blob/master/src/main/java/org/reactivejournal/examples/helloworld/HelloWorldApp_JounalAsObserver.java)\n\n### Play the stream in actual time or fast\n\nThe `RxPlayer` can `play` in two modes:\n* `ACTUAL_TIME` This plays back the stream preserving the time gaps between the events. This is\nimportant for back testing and reproducing exact conditions in unit tests.\n* `FAST` This plays the events as soon as they are received. This mode should be set when you are using \nReactiveJournal for remote connections or when using RxJounal to deal with back pressure.\n\n### Can ReactiveJournal be used in a low latency environment\n\nThe intention is for `ReactiveJournal` to support low latency programs. The two main features to allow\nfor this are:\n* Dedicating a CPU core to RxPlayer by using the `PlayOptions.setPauseStrategy(PauseStrategy.SPIN)` \nsetting so that we don't have any context switching on the thread reading from the journal.\n* Setting the `PlayOptions.using()` so that there is no allocation for new events. This should enable\nprograms to be written that have minimal GC impact, critical for reliable low latency.\n\n## Examples\n\nThere are few core example applications in the code that work through the typical\nuse cases and are worth considering in more detail.\n\n### HelloWorldApp_JournalPlayThrough\n\nThis program demonstrates how to set up a simple 'play through' example.\n \nWe have an input `Flowable` with a stream of `Byte`s. These are recorded in the journal \nby `ReactiveRecorder`.\n\nWe then subscribe to `ReactiveJournal` with `ReactivePlayer` giving us an `Flowable` of `Byte`s\nwhich are processed by the `BytesToWordsProcessor`. The output of the processor is \nalso recorded into `ReactiveJournal` so we have a full record of all our input and outputs to\nthe program.\n\nNote that we use `recordAsync` rather than `record` because otherwise we would \nblock the main thread until all the event stream had completed recording and only\nthen would we proceed to process the items. Although in this trivial example\nit's hard to see the effect this has I encourage you to play with the `INTERVAL_MS`\nsetting to see what happens as you increase the delay to something noticeable.\nThen try and change `recordAsync` to `async` and you will see the effect of\nthe threading.\n\nWe then display the results of the program to stdout as well as writing to a file.\n\nThis recording will be valuable when it comes to writing a unit test for \n`BytesToWordsProcessor` which we'll see in another example.\n\n### HelloWorldApp_JournalAsObserver\n\nThis is very similar to the last example except that we processes everything \non the same thread. We can do this because rather than the `BytesToWordsProcessor`\nsubscribing to `ReactiveJournal` it subscribes directly to the `Observable\u003cByte\u003e` input.\n\nThis is a less intrusive way to insert RxRecorder into your project but of\ncourse will not handle the back pressure problem.\n\n### HelloWorldTest\n\nThis example demonstrates how to use RxRecorder in a unit test. The journal file\nwe created in the previous examples is used as input to test the `BytesToWordsProcessor`.\nThe results of `BytesToWordsProcessor` are fed into `ReactiveValidator` which compares \nthe output to the output which was recorded in the journal reporting any \ndifferences. \n\nWe have effectively black boxed the inputs and outputs to `BytesToWordsProcessor` and can \nbe confident that any changes we make to the processor will not break the existing \nbehaviour.\n\n### HelloWorldRemote\n\nThis example is designed to show how ReactiveJournal can be used to tranfer data between JVMs.\n\nStart `HelloWorldApp_JournalPlayThrough` but increase the `INTERVAL_MS` to 1000. Then\nrun `HelloWorldRemote`.\n\n`HelloWorldRemote` has been configured with this option:\n\n```` java\nnew PlayOptions().filter(HelloWorldApp_JounalAsObserver.INPUT_FILTER).playFromNow(true);\n````\n\nThe playFromNow means that it will only consume current events and depending on how long \na gap you have between starting the 2 programs you will see output which looks something \nlike this:\n \n\n\n### Fast Producer Slow Consumer\n\nIn these example programs we deal with the situation where we find ourselves with a\nfast producer and slow consumer. \n\nIn all these example we setup a scenario in [`FastProducerSlowConsumer`]() where the\nproducer emits `Long` values every millisecond. We also create a `Consumer` which\nprocesses the Long values with a variable delay which is significantly slower\nthan the rate that they are being produced.\n\nIn other words we have the classic Fast Producer Slow Consumer scenario which needs\nto be handled by applying back pressure.\n\nThe following example programs have all been written to 'solve' the back pressure \nproblem we have created.\n\n#### RxJavaBackPressure\n\nFirstly let's consider how RxJava handles back pressure out of the box. \n\nA quick reminder, in RxJava2 the code was split into 2 sections:\n* `Observable` - no back pressure. Use when back pressure is not an issue because the\ncode is more efficient not having to deal with this complication.\n* `Flowable` - handles back pressure. Use when you have to address the back pressure issue.\n \nClearly we will only be looking at the `Flowable` part of RxJava2 in this example.\n\nThis example program demonstrates how the 5 `BackpressureStrategy` modes handle back\npressure.\n* `BUFFER` this will, as its name implies, hold the items in an in-memory buffer waiting\nfor availablility on the consumer to process them. This is good choice for handling spikes\nin event traffic where the consumer will eventually be able to catch up with the \nproducer. The problems using this strategy are:\n\n    * If the program crashes the events in the buffer will be lost. Even if the \n    program terminates normally careful attention has o be paid to draining the buffer.\n    * If the queue builds up too much the JVM will run out of memory and crash.\n    * It forces the program to run with a large memory setting to hold the buffer\n    which can be a problem for programs where latency is an issue especially coupled\n    with the next point.\n    * The program will not be able to be designed in an allocation-free manner. Every\n    item will have to be created in a 'new' object which will then put pressure on the GC.\n\n* `LATEST` and `DROP` deal with back pressure by making the slow consumer keep up with\nthe fast producer. This is done by dropping events from the stream. This is a good choice\nwhere events on the stream are replaceable and you don't need to process every item. The\nproblems with this straegy are:\n\n    * If you want to back test your program against all the values in the stream to see\n      if you might get better results by processing more events.\n    * As with buffer you can't write GC friendly code.\n    \n* `ERROR` and `MISSING` deal with back pressure by putting the program into an error state\nas soon as back pressure is encountered. This is useful when you don't expect any back pressure\nand you want the program to error on encountering back pressure. \n\n#### ReactiveJournalBackPressureBuffer\n\nIn this program we set up `ReactiveJournal` to handle back pressure in the buffer mode \nbut solving all the problems that we saw with the standard RxJava `BUFFER` mode.\n\nThe FastProducer can be created with\nthe `BackpressureStrategy.MISSING` because we don't expect that the producer will ever be\nslowed down by the consumer, which in this case is `RxRecorder`.\n\nThe Consumer, rather than subscribing directly to the FastProducer, subscribes to \n`RxPlayer`.  Note that `RxPlayer.play` returns an `Obserable` as there is no need for it to\nhandle back pressure because bakc pressure has already been applied using `ReactiveJournal` as the \nbuffer.\n\nLets look at the problems `BackpressureStrategy.MISSING` and see how they are solved.\n    \n* Even if the program crashes everything written to ReactiveJournal is safe. The events will be stored\n    to disk and you can just restart the program and carry on consuming the queue at the point \n    you crashed.  If there is a OS/Machine level issue it is possible that a few messages might\n    get lost that are waiting to be written to disk.  \n    If that is a problem you should make sure that replication is setup on your system.\n* There is no in-memory buffer so there is no need to run with extra heap memory and the program\ncertainly won't run out memory because of `ReactiveJournal`. \n* When you call `RxPlayer.play` one of the the options is `using`. This allows you to pass in the\nobject that will be used for every event. This means that no new objects will be allocated even\nif you have millions of items in your stream. (Of course if you want to hole a reference to the\nevent you will need to clone).\n\nIn addition to those benefits you will have the ususal benefits of using 'RxJornal' in that you\nwill have a full record of the stream to use in testing and you will be able to use remote\nJVMs.\n\n#### ReactiveJournalBackPressureLatest\n\nAs its name implies this demo program shows you how to handle back pressure using `ReactiveJournal`\nbut rather than buffer you just want the latest item on the queue.\n\nAll you have to do is set up the program exactly as we did in the previous example \n`ReactiveJournalBackPressureBuffer` but rather than the slow subscriber subscribing to the Observable\nthat comes from `RxPlayer.play` we insert a `Flowable` inbetween. The `Flowable` is created \nwith `BackpressureStrategy.LATEST`.\n\nSee code snippet from the example below:\n\n```java\n    //1. Get the stream of events from the RxPlayer\n    ConnectableObservable journalInput = reactiveJournal.createRxPlayer().play(options).publish();\n\n    //2. Create a Flowable with LATEST back pressure strategy from the ReactiveJournal stream\n    Flowable flowable = journalInput.toFlowable(BackpressureStrategy.LATEST);\n\n    //3. Record the output of the Flowable into the journal (note the different filter name)\n    recorder.record(flowable, \"consumed\");\n\n    long startTime = System.currentTimeMillis();\n    \n    //4. The slow consumer subscribes to the Flowable \n    flowable.observeOn(Schedulers.io()).subscribe(onNextSlowConsumer::accept,\n            e -\u003e System.out.println(\"RxRecorder \" + \" \" + e),\n            () -\u003e System.out.println(\"RxRecorder complete [\" + (System.currentTimeMillis()-startTime) + \"]\")\n    );\n```\n\nYou might have noticed that as well as the Slow Consumer subscribing to the Flowable to make\nsure it uses the LATEST strategy we also record the values we actaully consumer into ReactiveJournal.\n\nAs with the plain RxJava implementation of LATEST (without ReactiveJournal) the Slow Consumer\nonly sees the latest updates from the Fast Producer. However if you use RxRecorder (as in this\nexample) you have:\n* A full record of all the events that were emitted by the Fast Producer. \n* A full record of all the events that were actaully consumed by the Slow Producer.\n\nBoth these streams can be played back with `RxPlayer` by specifying the appropriate filter\nin the `PlayOptions` when calling `play`.\n\nThis leads to being ablse to try the following...\n\n#### ReactiveJournalBackPressureTestingFasterConsumer\n\nIn this example we experiment by replaying the event stream recorded in `ReactiveJournal` and \nobserving the effects of lowering the latency of the SlowConsumer.\n\nWe have a recording of the FastProducer created whilst running `ReactiveJournalBackPressureBuffer`.\nThe SlowConsumer subscribes to this using a `Flowable` with `BackpressureStrategy.LATEST`\nas in the provious example.\n\nWhen we run with the SlowConsumer at a latency of 5ms we get this result:\n\n````\nReceived [100] items. Published item[100]\nReceived [200] items. Published item[391]\nReceived [300] items. Published item[791]\nReceived [400] items. Published item[1175]\nReceived [500] items. Published item[1560]\nReceived [600] items. Published item[1946]\nReceived [700] items. Published item[2340]\nRxRecorder complete [3909ms]\n````\n\nThe Slow Consumer has managed to consume about 700 events.\n \nIf we reduce the latency of SlowConsumer to 3ms we get this result:\n\n````\nReceived [100] items. Published item[100]\nReceived [200] items. Published item[265]\nReceived [300] items. Published item[491]\nReceived [400] items. Published item[719]\nReceived [500] items. Published item[958]\nReceived [600] items. Published item[1192]\nReceived [700] items. Published item[1428]\nReceived [800] items. Published item[1664]\nReceived [900] items. Published item[2046]\nReceived [1000] items. Published item[2288]\nRxRecorder complete [3666ms]\n````\n\nThe Slow Consumer has now managed to consume about 1000 events.\n \nWhilst this is a trivial example I'll let your imagination extend the scenarios\nto real world situations where this sort of ability to replay data against real\nload will be invaluable.\n\n## Acknowlegments\n\nSpecial thanks to my friend and ex-collegue [Peter Lawrey](https://stackoverflow.com/users/57695/peter-lawrey)\nfor inspiring me with his [Chronicle libraries](https://github.com/OpenHFT) which underpin ReactiveJournal.\n\nTo those behind [RxJava](https://github.com/ReactiveX/RxJava) in particular to \n[Tomasz Nurkiewicz](http://www.nurkiewicz.com) for his talks and book which\nopened my eyes to RxJava.\n \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielshaya%2Freactivejournal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielshaya%2Freactivejournal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielshaya%2Freactivejournal/lists"}