<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8514295606932409163</id><updated>2024-10-05T07:02:34.258+03:00</updated><category term="Akka"/><category term="Eventsourcing"/><category term="Akka Persistence"/><category term="CQRS"/><category term="Gremlin"/><category term="Play2"/><category term="Scala"/><category term="Smartcards"/><category term="TinkerPop"/><category term="TitanDB"/><title type='text'>Digital Magic</title><subtitle type='html'>Digital Magic (www.digital-magic.io)</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://blog.digital-magic.io/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default'/><link rel='alternate' type='text/html' href='https://blog.digital-magic.io/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Digital Magic</name><uri>http://www.blogger.com/profile/03962649748428644767</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8514295606932409163.post-1272546609272022311</id><published>2018-12-20T14:07:00.000+02:00</published><updated>2018-12-21T16:33:39.482+02:00</updated><title type='text'>Removing the pesky Caps Lock delay on macOS Mojave</title><content type='html'>You may have noticed that in order to engage Caps Lock on your Apple computer, you have to hold the button down for about 100 milliseconds; shorter keypresses are just ignored.&lt;br /&gt;
&lt;br /&gt;
Personally, I type fast, and my keypresses are all equally brief, so in my case this &quot;feature&quot; causes Caps Lock mode to almost never get activated as expected, causing frustration.&lt;br /&gt;
&lt;br /&gt;
Apple does not seem to provide any means to configure this delay.&lt;br /&gt;
&lt;br /&gt;
Third-party solutions do exist, and I&#39;ve been using&amp;nbsp;&lt;a href=&quot;https://github.com/tekezo/Karabiner-Elements&quot;&gt;Karabiner-Elements&lt;/a&gt;&amp;nbsp;for a long time, which had a handy option to completely remove the said delay - until version 12, that is.&lt;br /&gt;
&lt;br /&gt;
Here is what the author has to &lt;a href=&quot;https://github.com/tekezo/Karabiner-Elements/issues/1349#issuecomment-381379081&quot;&gt;say&lt;/a&gt; about&amp;nbsp;&lt;a href=&quot;https://github.com/tekezo/Karabiner-Elements&quot;&gt;Karabiner-Elements&lt;/a&gt;&amp;nbsp;no longer offering the option:&lt;br /&gt;
&lt;div style=&quot;background-color: white; box-sizing: border-box; color: #24292e; margin-bottom: 16px;&quot;&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;i&gt;Since v12.0.0, Karabiner-Elements&#39;s virtual keyboard acts like the real hardware keyboard.&amp;nbsp;&lt;/i&gt;&lt;i style=&quot;background-color: transparent;&quot;&gt;Thus, macOS ignores the short press on caps lock.&lt;/i&gt;&lt;br /&gt;
&lt;span style=&quot;color: black;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;color: black;&quot;&gt;However,&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/tekezo/Karabiner-Elements&quot; style=&quot;background-color: transparent;&quot;&gt;Karabiner-Elements&lt;/a&gt;&amp;nbsp;still offers a way: it can hold the Caps Lock button &lt;b&gt;for&lt;/b&gt; you, so you don&#39;t have to :) That is, a brief physical keypress will turn into a longer &quot;virtual&quot; one automagically.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
Here is how.&lt;br /&gt;
&lt;br /&gt;
First, install&amp;nbsp;&lt;a href=&quot;https://github.com/tekezo/Karabiner-Elements&quot;&gt;Karabiner-Elements&lt;/a&gt;&amp;nbsp;and upgrade it to at least version 12.1.57 (which is beta as of the time of writing). In order to upgrade to a beta version, run&amp;nbsp;&lt;a href=&quot;https://github.com/tekezo/Karabiner-Elements&quot;&gt;Karabiner-Elements&lt;/a&gt;, open its Preferences screen and use the &quot;Check for beta updates&quot; option:&lt;/div&gt;
&lt;div style=&quot;background-color: white; box-sizing: border-box; color: #24292e; margin-bottom: 16px;&quot;&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;margin-left: 1em; margin-right: 1em; text-align: left;&quot;&gt;
&lt;a href=&quot;https://camo.githubusercontent.com/1786ffa5347cbc76e94386561c3756ccb24e69ac/68747470733a2f2f707172732e6f72672f6f73782f6b61726162696e65722f696d672f6b61726162696e65722d656c656d656e74732d636865636b2d666f722d757064617465732d626574614032782e706e67&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;217&quot; data-original-width=&quot;800&quot; height=&quot;173&quot; src=&quot;https://camo.githubusercontent.com/1786ffa5347cbc76e94386561c3756ccb24e69ac/68747470733a2f2f707172732e6f72672f6f73782f6b61726162696e65722f696d672f6b61726162696e65722d656c656d656e74732d636865636b2d666f722d757064617465732d626574614032782e706e67&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;
Now we need to create a &quot;Complex Modifications&quot; rule that would map the caps_lock key to itself, but being artificially held down for 100 milliseconds.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Create a text file with content posted below, and place it somewhere locally on your computer - for example, /tmp/remove_caps_lock_delay.json&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: white; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; color: #24292e; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #24292e;&quot;&gt;
Here is the text file content:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/minisaw/96a088445c8cd8af1a901a2445257dcc.js&quot;&gt;&lt;/script&gt;

&lt;br /&gt;
Now, open the following link in your Safari browser (make sure to replace /tmp/remove_caps_lock_delay.json if you have the file at another location):&lt;/div&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;&lt;a href=&quot;karabiner://karabiner/assets/complex_modifications/import?url=file:///tmp/remove_caps_lock_delay.json&quot;&gt;karabiner://karabiner/assets/complex_modifications/import?url=file:///tmp/remove_caps_lock_delay.json&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;You will be prompted to import the rule into Karabiner-Elements.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;After a successful import, open&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #24292e;&quot;&gt;Karabiner-Elements Preferences screen again, visit the &quot;&lt;/span&gt;&lt;span style=&quot;color: #24292e;&quot;&gt;Complex Modifications&quot; tab, press the &quot;Add rule&quot; button, and select &quot;Enable&quot; to the right of our newly imported &quot;Remove Caps Lock delay&quot; rule:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZiWqCEaoS2b8cY6nbq65NcTUNU6RDzzTMyKmDEnbB-PuHYtmg7Sh8D5MStp2GqnQBakNrQvMdZMC4YxDyUzQRN7k5qIY_PzQWd6Uq71p6I0I2uIeWLoICetrE_1Q_gQ4z5Vl0jdE7VlKs/s1600/Screenshot+2018-12-20+at+13.55.43.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;985&quot; data-original-width=&quot;1600&quot; height=&quot;393&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZiWqCEaoS2b8cY6nbq65NcTUNU6RDzzTMyKmDEnbB-PuHYtmg7Sh8D5MStp2GqnQBakNrQvMdZMC4YxDyUzQRN7k5qIY_PzQWd6Uq71p6I0I2uIeWLoICetrE_1Q_gQ4z5Vl0jdE7VlKs/s640/Screenshot+2018-12-20+at+13.55.43.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #24292e;&quot;&gt;To make the feature stable, set all timeouts to 100 milliseconds at the &quot;&lt;/span&gt;&lt;span style=&quot;color: #24292e;&quot;&gt;Complex Modifications&quot;&lt;/span&gt;&lt;span style=&quot;color: #24292e;&quot;&gt;&amp;nbsp;-&amp;gt; &quot;Parameters&quot; screen:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiszDXVPUB65GOF5Txb1db8FnSj7zBUSLCfysxTe5lF5yKHmQ0zxLd9pqnce4GArNdGGwuGeRPX7Ykqcqq4CUZ-cS4qY_eqAnLY1K0RvMnNYTalVxVF1uraWGSTZFZzzB9lIYfvNX0Ev37/s1600/Screenshot+2018-12-21+at+16.31.49.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;985&quot; data-original-width=&quot;1600&quot; height=&quot;392&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiszDXVPUB65GOF5Txb1db8FnSj7zBUSLCfysxTe5lF5yKHmQ0zxLd9pqnce4GArNdGGwuGeRPX7Ykqcqq4CUZ-cS4qY_eqAnLY1K0RvMnNYTalVxVF1uraWGSTZFZzzB9lIYfvNX0Ev37/s640/Screenshot+2018-12-21+at+16.31.49.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;That is all there is to it. No matter how briefly you press Caps Lock, Karabiner will &quot;hold&quot; it down long enough for macOS to recognize the keypress.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #24292e;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='https://blog.digital-magic.io/feeds/1272546609272022311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://blog.digital-magic.io/2018/12/removing-pesky-caps-lock-delay-on-macos.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default/1272546609272022311'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default/1272546609272022311'/><link rel='alternate' type='text/html' href='https://blog.digital-magic.io/2018/12/removing-pesky-caps-lock-delay-on-macos.html' title='Removing the pesky Caps Lock delay on macOS Mojave'/><author><name>Aleksei Irbe</name><uri>http://www.blogger.com/profile/14402596669774744614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZiWqCEaoS2b8cY6nbq65NcTUNU6RDzzTMyKmDEnbB-PuHYtmg7Sh8D5MStp2GqnQBakNrQvMdZMC4YxDyUzQRN7k5qIY_PzQWd6Uq71p6I0I2uIeWLoICetrE_1Q_gQ4z5Vl0jdE7VlKs/s72-c/Screenshot+2018-12-20+at+13.55.43.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514295606932409163.post-8202133220921709142</id><published>2017-08-05T00:04:00.000+03:00</published><updated>2017-08-05T00:04:39.103+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Akka"/><category scheme="http://www.blogger.com/atom/ns#" term="Gremlin"/><category scheme="http://www.blogger.com/atom/ns#" term="Scala"/><category scheme="http://www.blogger.com/atom/ns#" term="TinkerPop"/><category scheme="http://www.blogger.com/atom/ns#" term="TitanDB"/><title type='text'>TitanDB: why doesn&#39;t my index work ?</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2&gt;
The setting&lt;/h2&gt;
One of our customer&#39;s products is a Play2 application written in Scala on top of Lightbend Reactive Platform. The application takes advantage of a graph database –&amp;nbsp;&lt;a href=&quot;http://titan.thinkaurelius.com/&quot;&gt;TitanDB&lt;/a&gt;&amp;nbsp;1.0.0 in embedded mode, backed by Cassandra.&lt;br /&gt;
&lt;br /&gt;
TitanDB&amp;nbsp;allows fast and convenient queries across entities bound by relations (e.g. social networks).&lt;br /&gt;
&lt;br /&gt;
The application uses Titan&#39;s Java API to manipulate and query the graph.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
The problem&lt;/h2&gt;
At some point, we started noticing that certain queries were running really sluggishly – this was accompanied by Titan log messages such as this one:&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style=&quot;color: #666666; font-size: x-small;&quot;&gt;Query requires iterating over all vertices [(name = user001 AND ~label = agent)]. For better performance, use indexes&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
This was strange, as our application did check that the necessary indexes existed – and did create them if they weren&#39;t – at its start-up. The code looked something like this:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/LoneEngineer/6c9333e3b6bd3f8788dc3c54223fd0c6.js&quot;&gt;&lt;/script&gt;

&lt;br /&gt;
&lt;pre style=&quot;background-color: white;&quot;&gt;&lt;/pre&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
It was a surprise: a query that was expected to use an index actually did not. For the purposes of testing, I have manually ran a hand-crafted query that was definitely supposed to use that index and ... got the same result. Interesting.&lt;br /&gt;
&lt;br /&gt;
Scanning through&amp;nbsp;&lt;a href=&quot;http://s3.thinkaurelius.com/docs/titan/1.0.0/indexes.html&quot;&gt;index documentation&lt;/a&gt;&amp;nbsp;did not shed more light (well, there actually were hints at my problem on that page, but I&#39;ve missed them then). So what do software developers do when RTFM doesn&#39;t help? Right, Google it. I found a number of articles on StackOverflow, and I realized that TitanDB indexes had a lifecycle. I&#39;ve used the &#39;RTFS&#39; magical trick (read those sources :)) to get help:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; INSTALLED - The index is installed in the system but not yet registered with all instances in the cluster&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; REGISTERED - The index is registered with all instances in the cluster but not (yet) enabled&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; ENABLED - The index is enabled and in use&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; DISABLED - The index is disabled and no longer in use&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
So it&#39;s possible our indexes weren&#39;t enabled. The next step was to understand the statuses of our indexes – this can be done via the Gremlin console (there is also a programmatic way to do that from Scala):&lt;br /&gt;
&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt = g.getGraph().openManagement();&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;names = [ &quot;CompositeNameSalesperson&quot;, &quot;CompositeNameAgent&quot; ]; // &amp;lt;-- all indexes are here, actually&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;res = names.collect { [ it , mgmt.getGraphIndex(it).getIndexStatus(mgmt.getPropertyKey(&#39;name&#39;)) ] };&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.commit();&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;res&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
so we got something like this:&lt;br /&gt;
&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;background-color: white; color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;[&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;[CompositeNameSalesperson, ENABLED]&quot;,&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;[CompositeNameAgent, INSTALLED]&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Well-well, one of indexes is not enabled (and effectively is not used). And this is a new type of vertex, added few days ago.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
The fix&lt;/h2&gt;
Let&#39;s postpone finding the reason for the index being stuck in this INSTALLED lifecycle for a while. First order of business, I needed to repair the index by promoting it into the ENABLED state.&lt;br /&gt;
&lt;br /&gt;
Since my index is INSTALLED, the next state should be REGISTERED. Let&#39;s go:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt = g.getGraph().openManagement();&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.updateIndex(mgmt.getGraphIndex(&quot;CompositeNameAgent&quot;), com.thinkaurelius.titan.core.schema.SchemaAction.REGISTER_INDEX);&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.commit();&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now I checked the state of the index again:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt = g.getGraph().openManagement();&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;names = [ &quot;CompositeNameAgent&quot; ];&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;res = names.collect { [ it , mgmt.getGraphIndex(it).getIndexStatus(mgmt.getPropertyKey(&#39;name&#39;)) ] };&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.commit();&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;res&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
and got:&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;[&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;[CompositeNameAgent, INSTALLED]&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What ?! Why? Turned verbose logging on and I got:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: #666666; font-size: x-small;&quot;&gt;Some key(s) on index CompositeNameAgent do not currently have status REGISTERED: name=INSTALLED&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
The next iteration of &lt;i&gt;Seq(documentation, Google, StackOverlow).foreach(_.read)&lt;/i&gt;&amp;nbsp;has yielded the following list of possible reasons due to which changing the state of the index might fail:&lt;br /&gt;
- open transactions&lt;br /&gt;
- stalled Titan instances&lt;br /&gt;
&lt;br /&gt;
I was pretty sure nobody used Titan at that moment, so I went the second path to investigate. Hopefully, the Titan API can respond with enough information:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt = g.getGraph().openManagement();&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;y = mgmt.getOpenInstances();&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.commit();&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;y;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
and the response is:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;[ac1100041-hostname(current), ac1100041-hostname, ac1100021-hostname]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Hmm, so why are there 3 instances if I knew that only one application instance was running? Let&#39;s consult the documentation: &quot;&lt;i&gt;... TitanFactory can also be used to open an embedded Titan graph instance from within a JVM-based user application ...&lt;/i&gt;&quot; – this would explain the existence of 2 instances (we&#39;re a using the factory twice) but what about the 3rd one?&lt;br /&gt;
&lt;br /&gt;
Continuing reading the&amp;nbsp;&lt;a href=&quot;http://s3.thinkaurelius.com/docs/titan/1.0.0/failure-recovery.html&quot;&gt;documentation about failures&lt;/a&gt;&amp;nbsp;I got at my scenario:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;However, some schema related operations - such as installing indexes - require the coordination of all Titan instances. For this reason, Titan maintains a record of all running instances. If an instance fails, i.e. is not properly shut down, Titan considers it to be active and expects its participation in cluster-wide operations which subsequently fail because this instances did not participate in or did not acknowledge the operation.&amp;nbsp;&lt;/i&gt;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;In this case, the &lt;b&gt;user must manually remove the failed instance record&lt;/b&gt; from the cluster and then retry the operation.&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
Bingo! That&#39;s explains the reason for our inability to change the status of the index. The &quot;&lt;i&gt;ac1100021-hostname&lt;/i&gt;&quot; instance seems to be the black sheep here. Let&#39;s get rid of it:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;toRemove = [&quot;ac1100021-hostname&quot;];&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt = g.getGraph().openManagement(); &amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;x = mgmt.getOpenInstances(); &amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;toRemove.collect{ &amp;nbsp;mgmt.forceCloseInstance(it) };&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.commit(); &amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;y = mgmt.getOpenInstances(); &amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;[x, y];&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
that operation returned:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;[&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;[ac1100041-hostname(current), ac1100041-hostname, ac1100021-hostname]&quot;,&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;[ac1100041-hostname(current), ac1100041-hostname]&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now I have repeated the operations stated at the begging of this chapter and I got:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;[&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;[CompositeNameAgent, REGISTERED]&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
I did that! Finally let&#39;s enable index...&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt = g.getGraph().openManagement();&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.updateIndex(mgmt.getGraphIndex(&quot;CompositeNameAgent&quot;), com.thinkaurelius.titan.core.schema.SchemaAction.ENABLE_INDEX);&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.commit();&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
...and verify the result:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt = g.getGraph().openManagement();&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;names = [ &quot;CompositeNameAgent&quot; ];&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;res = names.collect { [ it , mgmt.getGraphIndex(it).getIndexStatus(mgmt.getPropertyKey(&#39;name&#39;)) ] };&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;mgmt.commit();&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;res&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
we finally get:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #666666; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;b&gt;[CompositeNameAgent, ENABLED]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
I&#39;ve checked the original query (which was suppose to use the index) - and it ran as fast as other queries. Problem solved! But wait a minute! Game is not over.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Root causes&lt;/h2&gt;
So why did the index get stuck in the &#39;INSTALLED&#39; state in the first place? (also I recall seeing some of the indexes being stuck in the &#39;REGISTERED&#39; state)&lt;br /&gt;
&lt;br /&gt;
I end up with 2 possible reasons:&lt;br /&gt;
&lt;br /&gt;
a. In case an application instance (with an embedded Titan instance) crashes, it remains intact in Titan bookkeeping as a cluster member – this dead instance prevents index state from progressing, as it can not be communicated with. The following log records can be observed in this case:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: #666666; font-size: x-small;&quot;&gt;Some key(s) on index CompositeNameAgent do not currently have status ENABLED: name=REGISTERED&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: #666666; font-size: x-small;&quot;&gt;...&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: #666666; font-size: x-small;&quot;&gt;Timed out (PT1M) while waiting for index CompositeNameAgent to converge on status ENABLED&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
An advice: make sure there are no dangling Titan cluster members - clear them our prior to creating indexes (or doing any other cluster-wide operation).&lt;br /&gt;
&lt;br /&gt;
b. An issue with the code which creates indexes:&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; val index = management.buildIndex(indexName, classOf[Vertex]).addKey(key).indexOnly(label).unique().buildCompositeIndex()&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; management.setConsistency(index, ConsistencyModifier.LOCK)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Reading through Titan documentation and StackOverflow articles, I have found that this call returns as soon as the index has entered the INSTALLED state. To be sure that the index has actually entered the ENABLED state (and hence is actually ready to be used by queries), it is required to wait for index creation completion outside the transaction where it was created, and make sure no other transactions bother us. So the index setup code (see the beginning of the article) was changed to:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/LoneEngineer/6afd799cf45974222ca993ae6b26fd60.js&quot;&gt;&lt;/script&gt;

&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='https://blog.digital-magic.io/feeds/8202133220921709142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://blog.digital-magic.io/2017/08/titandb-why-doesnt-my-index-work.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default/8202133220921709142'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default/8202133220921709142'/><link rel='alternate' type='text/html' href='https://blog.digital-magic.io/2017/08/titandb-why-doesnt-my-index-work.html' title='TitanDB: why doesn&#39;t my index work ?'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/10579543887199382888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514295606932409163.post-2186280275441993570</id><published>2017-07-31T17:24:00.001+03:00</published><updated>2017-08-01T13:18:21.045+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Akka"/><category scheme="http://www.blogger.com/atom/ns#" term="Eventsourcing"/><category scheme="http://www.blogger.com/atom/ns#" term="Play2"/><category scheme="http://www.blogger.com/atom/ns#" term="Smartcards"/><title type='text'>Indoor shooting range: automated billing and admissions</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;In this blog entry we will share a business case of Digital Magic helping a business evolve a fledgling idea into a mature product.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The setting&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;A while back a person has decided to establish an indoor shooting range business. His plan was to refurbish an abandoned factory building and hire an administrator who would deal with shooting range customer admissions.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The problem&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Selling bullets or cartridges, it is easy to ensure that every item has been accounted for by comparing the physical state of ammo inventory to the amount of cash the company account has received since the last inventory. This is not so with &quot;shooting time&quot;, which is not easily tangible.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Simply put, the business owner wanted to ensure that shooting time is correctly&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&amp;nbsp;inventoried.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The concept&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The business owner came up with an idea – separating the two conflicting concerns out:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;admissions sales&lt;/b&gt; would be handled by the administrator&lt;/li&gt;
&lt;li&gt;&lt;b&gt;physical access&lt;/b&gt; to a shooting lane and &lt;b&gt;customer billing&lt;/b&gt; would be handled completely by an automated system&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The business owner then approached us – the Digital Magic team – with this idea and asked to help make it real.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The solution&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;We sat together with the business owner, analysing the idea, crystallising it into a vision of an actual product.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;One of the fundamental questions was the identification of a customer account with which to associate credit. Having discarded technologies such as loyalty cards, RFID stamps, optical face recognition and mobile phone-based IDs, we have converged at customer identification based on smart cards. To be more precise, &lt;a href=&quot;https://en.wikipedia.org/wiki/Estonian_ID_card&quot;&gt;Estonian ID cards&lt;/a&gt; (as the business resides in Estonia, where every resident possesses such a card).&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The solution was then straightforward:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;each shooting lane would be equipped with:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;its own lighting&lt;/li&gt;
&lt;li&gt;a rail running along the ceiling allowing the target to be brought closer to or further away from the firing point&lt;/li&gt;
&lt;li&gt;an electric motor controlled by a joystick that would actually move the target&lt;/li&gt;
&lt;li&gt;a smart card reader&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;initially, all shooting lanes would have their lights off, and their targets brought close to the firing point, which renders shooting impossible (or at least no fun :))&lt;/li&gt;
&lt;li&gt;a customer would enter the shooting range and buy a certain time allowance from the administrator&lt;/li&gt;
&lt;li&gt;using a management console, the administrator would associate the credit with the customer’s account, based on his smart card ID number&lt;/li&gt;
&lt;li&gt;the client would then approach a shooting lane and insert his ID smart card into that lane’s card reader&lt;/li&gt;
&lt;li&gt;the system would turn the lane’s lights on, and power the electric motor joystick on so that the customer could move the target as far away from the firing point as he wishes&lt;/li&gt;
&lt;li&gt;the system would track the time during which the smart card resides within the card reader&lt;/li&gt;
&lt;li&gt;as soon as credit runs out (or the card gets removed), the system would turn the lane’s lights off and retract the target close to the firing range, powering the joystick down, effectively denying the customer the ability to shoot.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The design&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The business owner took care of installing high-current electrics and devices: each shooting lane was now equipped with lighting, electrical motors shifting the shooting target along the rail, and motor control joysticks - all connected to a power source. Each lane could now individually be powered up or down by simply closing the corresponding pair of wires.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Actual activation and deactivation of each lane was now up to an intelligent system, which&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&amp;nbsp;- both hardware and software - was to be designed, implemented and installed by Digital Magic.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The diagram below depicts the overall design:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhLRUITb1rIkQzoWMeZyuYIMutx_YH3A3lXzVQ73VGnpAs1YXDsgifrS9c3vrFd9zzN0IciSyiMEIwL0RNj1fZcfhovTbfSlrdomzJQtxsmIU0dObauFOAeOQV5kTAX_jHIiDgG-UD2g1y/s1600/shooting+range+-+Page+1+%25287%2529.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1504&quot; data-original-width=&quot;1600&quot; height=&quot;601&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhLRUITb1rIkQzoWMeZyuYIMutx_YH3A3lXzVQ73VGnpAs1YXDsgifrS9c3vrFd9zzN0IciSyiMEIwL0RNj1fZcfhovTbfSlrdomzJQtxsmIU0dObauFOAeOQV5kTAX_jHIiDgG-UD2g1y/s640/shooting+range+-+Page+1+%25287%2529.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Hardware&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;First order of business was to choose a controller that would become the bridge between the software customer account management system and the high-current hardware lane controls.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;We have chosen the &lt;a href=&quot;http://kernelchip.ru/Laurent-112.php&quot;&gt;Laurent-112 Ethernet network relay&lt;/a&gt;, which has the ability to:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;control all 7 shooting lanes (there are 12 relays on the PCB)&lt;/li&gt;
&lt;li&gt;connect to Ethernet and expose a HTTP server with a simple API&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The next piece of hardware were smart card readers - we just used generic&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;USB&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;readers. One challenge was that the firing points were some distance away from the server room, so each reader USB cable was extended with 20+ meter long extension cables each featuring a signal repeater.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The server running the actual management application is a simple office PC running Ubuntu, too boring for its specs to be listed :) One requirement for the PC, though, was having at least 7 USB ports - one for each shooting lane. We have also tried connecting all readers via an USB hub with success - the server could still discern individual card readers - but eventually settled on the simpler hub-less solution.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Software&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The application server is the brain behind the operation.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;It is an application based on &lt;a href=&quot;https://www.playframework.com/&quot;&gt;Play&lt;/a&gt; and Akka Persistence - you can read more about the latter technology in &lt;a href=&quot;http://blog.digital-magic.io/2016/04/practical-akka-persistence.html&quot;&gt;this blog post&lt;/a&gt;, however the choice of frameworks did not matter much for this business case, as the project was small-scale.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The application server is hooked up as follows:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;7 smart card readers (installed at each shooting lane&#39;s firing point) are connected directly to the PC&#39;s 7 USB ports.&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Ubuntu gives each USB port a name; server configuration binds each port name to its shooting lane.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;the PC is connected to the Laurent-112 controller via Ethernet.&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;The controller can be sent simple commands via HTTP using a &lt;a href=&quot;http://kernelchip.ru/download/Laurent-112/Laurent-112_Manual_v.1.02.pdf&quot;&gt;proprietary protocol&lt;/a&gt; to:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;close a relay, activating a particular shooting lane&lt;/li&gt;
&lt;li&gt;open a relay, turning that lane&#39;s lights off&lt;/li&gt;
&lt;li&gt;check relay status&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Server configuration binds each relay to its shooting lane.&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The application server&#39;s main responsibility is listening to&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://docs.oracle.com/javase/7/docs/jre/api/security/smartcardio/spec/javax/smartcardio/package-summary.html&quot;&gt;javax.smartcardio&lt;/a&gt; smart card&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;events:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;whenever an ID card is inserted into the card reader of shooting lane N, the customer account associated with the card is checked for credit availability&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;if there is enough credit, a &quot;close relay N&quot; command is sent to the Laurent-112 controller, activating the corresponding lane&lt;/li&gt;
&lt;li&gt;the system starts tracking passage of time with 1-second resolution for that lane.&lt;/li&gt;
&lt;li&gt;as soon as customer&#39;s credit gets depleted, the application disengages the shooting lane.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;whenever an ID card is removed from the card reader of&amp;nbsp;shooting lane N,&amp;nbsp;an &quot;open relay N&quot; command is sent to the Laurent-112 controller, deactivating the corresponding lane.&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The application server also exposes the following functionality via WEB-based management consoles:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;a WEB UI for the shooting range administrator&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;associate credit with a customer&#39;s account&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;a WEB UI for the business owner&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;create and delete administrator accounts&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;create tariff plans&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;request billing reports:&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;hourly customer activity reports&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;summary of customer payments during a time period&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The bottom line&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Using billing reports generated by the system, the business owner was now able to&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;easily inventory shooting time by comparing banking account cash flows to the amount of credit sold as registered by the system.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Problem solved.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Application server frameworks&lt;/span&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Play 2&lt;/li&gt;
&lt;li&gt;Akka Persistence + LevelDB backend (very light loads)&lt;/li&gt;
&lt;li&gt;javax.smartcardio to interact with smart cards&lt;/li&gt;
&lt;li&gt;written in Scala&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Issues we&#39;ve encountered&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;On a rare occasion, e.g. sometimes upon Ubuntu server reboot, the USB port names would change (so that e.g. the first shooting lane&#39;s card reader, which was previously named &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;OMNIKEY CardMan 1021 01 00&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;, would now be named e.g. &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;OMNIKEY CardMan 1021 06 00&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;). The occasions were so rare that the business owner had no trouble fixing them by re-mapping ports via the WEB management console.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;In order to correctly handle application crashes or application server hardware failures, the Laurent-112 PCB needs to be configured to periodically ping the application to sense outages - in such cases, the PCB would open all relays, deactivating all shooting lanes, as&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;by this moment&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;the main application has lost the ability to track credit. At this particular installation, we have not done so, but it is perfectly possible by e.g. running the application as a Docker container with a heartbeat port exposed. Any kind of a crash would render the port inaccessible.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Ideas for the future&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Additional reports, such as a heat map report, which would help answering questions such as:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;which are peak customer activity hours?&lt;/li&gt;
&lt;li&gt;which are the best business hours?&lt;/li&gt;
&lt;li&gt;should additional shooting lanes be built?&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Also, the list of services offered by the automated system could be extended to selling not just shooting time, but also guns, ammo and targets, each with their automatically calculated prices based on tariffs, client track record, campaigns, etc.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='https://blog.digital-magic.io/feeds/2186280275441993570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://blog.digital-magic.io/2017/07/indoor-shooting-range-automated-billing_31.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default/2186280275441993570'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default/2186280275441993570'/><link rel='alternate' type='text/html' href='https://blog.digital-magic.io/2017/07/indoor-shooting-range-automated-billing_31.html' title='Indoor shooting range: automated billing and admissions'/><author><name>Aleksei Irbe</name><uri>http://www.blogger.com/profile/14402596669774744614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhLRUITb1rIkQzoWMeZyuYIMutx_YH3A3lXzVQ73VGnpAs1YXDsgifrS9c3vrFd9zzN0IciSyiMEIwL0RNj1fZcfhovTbfSlrdomzJQtxsmIU0dObauFOAeOQV5kTAX_jHIiDgG-UD2g1y/s72-c/shooting+range+-+Page+1+%25287%2529.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514295606932409163.post-6376084686974194286</id><published>2016-04-14T17:30:00.001+03:00</published><updated>2017-08-03T18:49:38.534+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Akka"/><category scheme="http://www.blogger.com/atom/ns#" term="Akka Persistence"/><category scheme="http://www.blogger.com/atom/ns#" term="CQRS"/><category scheme="http://www.blogger.com/atom/ns#" term="Eventsourcing"/><title type='text'>Practical Akka Persistence</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-weight: normal;&quot;&gt;Having used Akka Persistence in a live project, we at &lt;a href=&quot;http://www.digital-magic.io/&quot;&gt;Digital Magic&lt;/a&gt; have decided to write our experience down as a blog post. Here you&#39;ll find practical advice that would help you start using the framework, side-stepping the rough edges.&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Familiarity with the actor model and its Akka implementation are assumed. Familiarity with Scala would help.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large;&quot;&gt;What does Akka Persistence get you&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Akka actors lose their internal state when stopped. Quite simply, the Akka Persistence framework enables stateful actors to:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;persist their state to a durable store of your choice&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;recover actor state&amp;nbsp;from a persistent store&amp;nbsp;at actor startup&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;For example, you can model shopping cart entities as stateful actors. In case your application crashes and gets restarted, the in-memory state of your shopping cart actors would automatically be restored by the framework to the pre-crash state; the users of the system would keep shopping as if nothing has happened.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;A little theory first.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large;&quot;&gt;Event Sourcing&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 1.295; white-space: pre-wrap;&quot;&gt;Traditionally, an application keeps a snapshot of its current state in a database. Suppose the following actions have been performed by a system user:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;a group G was created&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;a couple of users A and B were created&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;user A was added to the group&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;user B was added to the group&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;user A was removed from the group&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The resulting state (in e.g. RDBMS) looks like follows:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;img alt=&quot;https://documents.lucidchart.com/documents/ebec7350-2d39-4c75-ae4b-55ac13bf6f6a/pages/TEt6q_3QyzB1?a=209&amp;amp;x=143&amp;amp;y=68&amp;amp;w=374&amp;amp;h=264&amp;amp;store=1&amp;amp;accept=image%2F*&amp;amp;auth=LCA%204c2c13fb4ef259b5d19956ae0a74b4058e84a052-ts%3D1458838848&quot; height=&quot;198&quot; src=&quot;https://lh4.googleusercontent.com/OOV2fW9ituZhyRQot0Fv5XmqX8DgqPTzCZOsD-7cxvssMoiAOk2lBprFFhDCppW8kRglFoFjFTZitKRQI3VWqkjtdrLqkOHS9GDgSV5kWZtb6YtFqhg0-OzopUnZIaaSx-aWxyb1iFs_66OrYA&quot; style=&quot;-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);&quot; width=&quot;281&quot; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;The history of events that has led to this particular state is not recorded. Was user A ever a member of the group?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;With event sourcing, instead of saving &lt;/span&gt;&lt;span style=&quot;font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;current &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;application state, a sequential &lt;b&gt;log &lt;/b&gt;of &lt;/span&gt;&lt;span style=&quot;line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;incremental &lt;/span&gt;&lt;span style=&quot;font-weight: 700; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;changes&lt;/span&gt;&lt;span style=&quot;line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; to the state is stored&lt;/span&gt;&lt;span style=&quot;line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;. Each state change is captured in an event - an immutable fact of the past, something that has already happened. The&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;line-height: 1.295;&quot;&gt;&lt;span style=&quot;line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; event log is &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-weight: 700; line-height: 1.295; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;append-only&lt;/span&gt;&lt;span style=&quot;line-height: 1.295; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;, with no events ever updated or removed.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 1.295; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;In order to reconstruct the current application state, all past events are replayed in their original order, and sequentially applied to the working state using a deterministic function {old state, event} =&amp;gt; {new state}.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 1.295; white-space: pre-wrap;&quot;&gt;A familiar example of a system based on event sourcing is a version control system. Every repository change is captured as a commit, and you rebuild the current state of the code base by replaying all the com&lt;/span&gt;&lt;span style=&quot;line-height: 1.295; white-space: pre-wrap;&quot;&gt;mits into an empty directory.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-13c4-81a5-dc3d-ed1e37a6b72b&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Event sourcing can also be found in real world businesses – e.g. doctors gradually appending data to your medical profile, or formal contracts being updated by the means of addendums (not striking words out from the original contract).&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h4 style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal; white-space: pre-wrap;&quot;&gt;Advantages of event sourcing&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;With Event Sourcing, you have a complete log of every change ever applied to the system. This opens up business opportunities such as:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Additional data insight. Data about your business is value. For example, in case some day in the future you decide it would be opportune to know the set of items your customers remove from their shopping carts right prior to checking out, you would be capable of having such a report retrospectively, not just &quot;from that day forward&quot;.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;A complete audit trail - for free.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 1.295; white-space: pre-wrap;&quot;&gt;Excellent write performance characteristics due to &quot;append-only&quot; write pattern.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Easy to scale the write store up because there is no write contention or locking.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 1.295; white-space: pre-wrap;&quot;&gt;Easy to reproduce issues for debugging purposes – just replay the event log up to a particular point in time and debug from there.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The stream of events up to the point of failure might even become your test case setup.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;Drawbacks of event sourcing&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;div style=&quot;margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 20.72px; white-space: pre-wrap;&quot;&gt;One drawback is an increased storage capacity requirement, as data&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;line-height: 20.72px; white-space: pre-wrap;&quot;&gt;gets &lt;/span&gt;&lt;span style=&quot;line-height: 20.72px; white-space: pre-wrap;&quot;&gt;never deleted. But data is value, so one might actually argue this is a drawback at all.&lt;/span&gt;&lt;span style=&quot;line-height: 20.72px; white-space: pre-wrap;&quot;&gt;However, the biggest problem is that with event sourcing, it is troublesome to query data.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.72px;&quot;&gt;All you have is an event log. How do you answer queries such as &quot;is user B a member of group G&quot;? Replaying the complete log each time in order to answer a query would be very sad, indeed.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.72px;&quot;&gt;How do you answer queries that need data to be aggregated from several event logs?&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;line-height: 1.295;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;In order to combat the log querying problems, let&#39;s take advantage of the idea of CQRS, discussed next.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;h3&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h3&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large;&quot;&gt;CQRS&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;CQRS stands for Command and Query Responsibility Segregation. The idea is quite simple: you can have the same data, but different data models for reads and writes&lt;span style=&quot;line-height: 1.38;&quot;&gt;. Turn the log of events into a model more suitable for querying by projecting event store(s) into query store(s).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;
&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span style=&quot;line-height: 1.38;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;CQRS can be depicted as:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-7b320412-13f1-d61b-9421-3618f4407b9b&quot; style=&quot;white-space: pre-wrap;&quot;&gt;&lt;img height=&quot;425px;&quot; src=&quot;https://lh6.googleusercontent.com/OOGm_CDcqv8tZlEf7QV2_8q7TwMbutUFAYB5n5KLukKjSfTjJ-PDGI0ffZ7PUXFMvnoqnQQ7z4gv4rST3d_C31LYfTfw3e6SrfTEX425r_-YwltrYPHNLjNRaPVp5HcfXhpuDZZEGxk&quot; width=&quot;482px;&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h4 style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;span style=&quot;font-size: large; font-weight: normal; line-height: 18.9934px;&quot;&gt;Advantages of CQRS&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;line-height: 18.9934px;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;First and foremost, CQRS enables event sourcing to be practically applicable, by providing a way for data to be queried.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 18.9934px;&quot;&gt;An important observation is that a single data model simply can not be equally appropriate for all kinds of queries as well as for writes at the same time. Trying to have a single data model fit everywhere adds inherent complexity to the system.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 18.9934px;&quot;&gt;With CQRS, you can optimize the write and query stores independently. &lt;/span&gt;&lt;span style=&quot;line-height: 18.9934px;&quot;&gt;You might want to store the event log in a data store optimized for sequential append-only writes (such as Cassandra), while having your audit trail reside in Elasticsearch specializing in full-text search, still having your documents served by MongoDB.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 18.9934px;&quot;&gt;You might project portions of your data into a relational database and have the tables optimized for queries by giving up normal forms, not worrying about data duplication or data inconsistencies because there is only one system of record - the event log, from which the query stores may be rebuilt at any time.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 18.9934px;&quot;&gt;Another benefit is that you can scale your read stores independently of write stores.&amp;nbsp;It is typical for q&lt;/span&gt;&lt;span style=&quot;line-height: 18.9934px;&quot;&gt;ueries to happen orders of magnitude more often than writes&lt;/span&gt;&lt;span style=&quot;line-height: 18.9934px;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h4 style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-size: large; font-weight: normal; line-height: 18.9934px;&quot;&gt;Drawbacks of CQRS&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;div style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;line-height: 18.9934px;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The query side has to be prepared that their requests will be served with relaxed (eventual) consistency. This is due to that the projection of the write store to the query store is typically non-instantaneous. However, read on about serving simple queries in a consistent manner from an in-memory state.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 18.9934px;&quot;&gt;CQRS also implies increased storage capacity requirements, as the same data resides in several data stores (and probably in non-normal forms, as well).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: x-small;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-size: large;&quot;&gt;Akka Persistence&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;In short, the Akka Persistence framework is an implementation of Event Sourcing and CQRS on top of Akka.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;Akka Persistence comprises of the following components:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Persistent Actor&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Event Journal&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Snapshot Store&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Akka Persistence Query (experimental API as of Akka 2.4)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;At-least-once delivery&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Persistent FSM (experimental API as of Akka 2.4)&lt;/span&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;Let&#39;s cover each of these separately.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;h4 style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-size: large; font-weight: normal;&quot;&gt;Persistent Actor&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;If you wish your entity actor&#39;s state to be protected from loss at stop or crash, and recovered at actor startup, use the Persistent Actor interface.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;The key concepts around the interface are:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Commands - these are i&lt;/span&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;mperative instructions for the actor to do something, they are p&lt;/span&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;lain vanilla Akka messages. A command may or may not result in a state change.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Events - the same concept as discussed in the Event Sourcing section. Events capture state changes, and are &lt;/span&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;immutable facts of the past.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;State - the working state of an actor is the sum &lt;/span&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;of sequential application of all the events, using a deterministic application function.&lt;/span&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Here is an example of the concepts bound together:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span id=&quot;docs-internal-guid-eff1c4f2-141d-51a2-e2c6-39bf15170d4d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;img height=&quot;328px;&quot; src=&quot;https://lh4.googleusercontent.com/LkTd26XS9N-ul-v6pBde82nQjNbBC8iZ1eCkm_D-IJlYvu5_8ionC_WpHija2BYJ8vxhEScPq4WHV-mdXWikkml7FkDzf4Axv1QvPaRxPuNTY8wEWaCkaIDBtTNhThkGBtv4W4ij_CE&quot; width=&quot;470px;&quot; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Suppose a user management actor is commanded to grant the administrator role to the user identified by rob@corp.com. The actor first checks whether such a user exists, whether he already has such a role, whether the acting user has enough rights to grant roles to other users, etc... In case all such checks pass, an event is created (note the past tense &quot;role has been added&quot;). In order to update the actor state (so that it would reflect the effects of the event), the deterministic event application function {old state, event} =&amp;gt; {new state} is called as displayed above.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;h4&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;
Event Journal&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;This concept is the same as was discussed in the Event Sourcing section. An event journal is an append-only immutable log of events. Each persistent actor has exactly one journal, identified by a persistenceId, and you must ensure that no two actors within a cluster have the same persistenceId. Persistent actors have to be cluster singletons.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;The event journal can be backed by a selection of data stores, and there is a number of community plugins for RDBMS, NoSQL, document stores, etc... Cassandra seems to be a good fit for the event journal backing store, because it is optimized for writes.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;Let&#39;s consider an example.&amp;nbsp;&lt;span style=&quot;line-height: 1.295; white-space: pre-wrap;&quot;&gt;Below is a simple example of a domain model:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;&lt;span style=&quot;line-height: 1.295; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320417-13e5-d1b1-a676-d0513d373b24&quot;&gt;&lt;span id=&quot;docs-internal-guid-7b320412-13f0-8dde-de89-1ecca8c3b2a4&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;object &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Domain {&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// Commands – the external stimuli, these do not get persisted&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;sealed trait &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Command&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case class &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Deposit(amount: Int) &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Command&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case class &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Withdraw(amount: Int) &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Command&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// Events - reflect effects that have already happened&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;sealed trait &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Event&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case class &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;BalanceChanged(delta: Int) &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Event&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// State - reflection of a series of events&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case class &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Account(balance: Int) {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;    // &lt;span style=&quot;font-style: italic; line-height: 14.4px;&quot;&gt;the deterministic event application function&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;def &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;apply(event: Event) = event &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;match &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;
&lt;/span&gt;
&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(balance &amp;gt;= 0)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;BalanceChanged&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(delta) =&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Account&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(balance + delta)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;}&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;
&lt;/span&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt; white-space: pre-wrap;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Actors who would like their state persisted have to inherit the PersistentActor trait:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;font-family: &#39;Courier New&#39;; font-size: 12px; line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; white-space: pre-wrap;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;class &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;Account(val id: String) &lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;text-decoration: underline; vertical-align: baseline;&quot;&gt;PersistentActor&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt;// this identifies the persistent journal and&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-style: italic; line-height: 1.2;&quot;&gt;  // does not change between actor incarnations&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-style: italic; line-height: 1.2; vertical-align: baseline;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; line-height: 1.2; vertical-align: baseline;&quot;&gt;override val &lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-style: italic; line-height: 1.2; text-decoration: underline; vertical-align: baseline;&quot;&gt;persistenceId&lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-style: italic; line-height: 1.2; vertical-align: baseline;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;line-height: 1.2; vertical-align: baseline;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; line-height: 1.2; vertical-align: baseline;&quot;&gt;s&quot;Account.$id&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;font-family: &#39;Courier New&#39;; font-size: 12px; line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; white-space: pre-wrap;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-style: italic; vertical-align: baseline;&quot;&gt;state &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;font-style: italic; vertical-align: baseline;&quot;&gt;Domain.Account&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;(balance = &lt;/span&gt;&lt;span style=&quot;color: blue; vertical-align: baseline;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt;// receives events during actor startup&lt;/span&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;override def &lt;/span&gt;&lt;span style=&quot;text-decoration: underline; vertical-align: baseline;&quot;&gt;receiveRecover&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #20999d; vertical-align: baseline;&quot;&gt;Receive &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;= {&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;ev: Event =&amp;gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-style: italic; vertical-align: baseline;&quot;&gt;state &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-style: italic; vertical-align: baseline;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;.apply(ev)&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;font-family: &#39;Courier New&#39;; font-size: 12px; line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; white-space: pre-wrap;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-style: italic; vertical-align: baseline;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt;// receives commands during normal operation&lt;/span&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;override def &lt;/span&gt;&lt;span style=&quot;text-decoration: underline; vertical-align: baseline;&quot;&gt;receiveCommand&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #20999d; vertical-align: baseline;&quot;&gt;Receive &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;= {&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;font-style: italic; vertical-align: baseline;&quot;&gt;Withdraw&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;(amount) =&amp;gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;if &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-style: italic; vertical-align: baseline;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;.balance &amp;lt; amount) {&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sender() ! &lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt;&quot;not enough funds&quot;&lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: 700; vertical-align: baseline;&quot;&gt;else &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt;// the callback is asynchronous, but Akka guarantees&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-style: italic; line-height: 1.2;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// is safe to access and update the state&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;font-family: &#39;Courier New&#39;; font-size: 12px; line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; white-space: pre-wrap;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;color: grey; font-style: italic; vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;text-decoration: underline; vertical-align: baseline;&quot;&gt;persist&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-style: italic; vertical-align: baseline;&quot;&gt;BalanceChanged&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;(-amount)) { changed =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;color: #980000; font-weight: 700; line-height: 1.2; vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #6aa84f; font-weight: 700; line-height: 1.2; vertical-align: baseline;&quot;&gt;// the only safe place to apply state mutation caused by the event&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;font-family: &#39;Courier New&#39;; font-size: 12px; line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; white-space: pre-wrap;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-style: italic; vertical-align: baseline;&quot;&gt;state &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-style: italic; vertical-align: baseline;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;.apply(changed)&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sender() ! &lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt;s&quot;successfully withdrawn &lt;/span&gt;&lt;span style=&quot;color: #00b8bb; font-weight: 700; vertical-align: baseline;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;color: green; font-weight: 700; vertical-align: baseline;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;color: #980000; font-weight: 700; line-height: 1.2;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// WRONG: state.getBalance is in unpredictable state&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;color: #980000; font-weight: 700; line-height: 1.2;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// sender() ! state.getBalance&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;line-height: 1.2;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;font-family: &#39;Courier New&#39;; font-size: 12px; line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; white-space: pre-wrap;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt; &amp;nbsp;}&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;About actor state&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The Akka persistence API does not specify the way an actor’s state is to be kept. A good choice is to keep an actor’s state in a single variable, because:
&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;li&gt;when you start using snapshots it’d be easier to write the whole state in one shot&lt;/li&gt;
&lt;li&gt;it’s easy to forget to update something if state is scattered over a dozen var  variables or behaviour parameters&lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;It’s a good idea to split an actor state into two parts: persistent and transient. The transient part must be reconstructable from the persistent part at any moment. An example is a dictionary of something (id -&amp;gt; object) and a reverse index (object -&amp;gt; id). During recovery, it is advised to reconstruct transient state only after recovery completion, to save up on computational resources.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Snapshot Store&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;State snapshots are completely optional. A snapshot captures an actor’s current internal state. Snapshots can&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;periodically &lt;/span&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;be&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;written out to bound recovery times of long journals.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;For example, suppose an actors has written 3 events, then a snapshot of the state reflecting those 3 events, and then two more events:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-daaf0fe5-142d-94dc-b111-4048383e3428&quot;&gt;&lt;img height=&quot;140px;&quot; src=&quot;https://lh3.googleusercontent.com/h3Q-KyOHtK8bLmDm8Ipwr-YSmBKiyGa0Q0z3mNBrXWFJXQt1oBOoQBnYrsP1l3IByWyCXNomDazgn3Fpmoj-t37eSprRczDA-XmogLJQK4w4Wn63f5iNqaLysvQBsDC-k14pvPaX-E4&quot; width=&quot;687px;&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: pre-wrap;&quot;&gt;In this case, upon actor st&lt;span style=&quot;font-family: inherit;&quot;&gt;artup, state recovery starts off with the latest snapshot, not an empty state, so only the events 4 and 5 will have to be read and applied.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;line-height: 14.4px; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Generally, here&#39;s how an actor is started up:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 14.4px; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;line-height: 14.4px;&quot;&gt;Run constructor, set initial state to empty&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;line-height: 14.4px;&quot;&gt;Receive latest snapshot, if any, and replace the initial state&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;line-height: 14.4px;&quot;&gt;Reconstruct the current actor state:&lt;/span&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;line-height: 14.4px;&quot;&gt;if there was a snapshot, apply only those events coming after it&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;line-height: 14.4px;&quot;&gt;if there are no snapshots, apply all events&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;line-height: 14.4px;&quot;&gt;in both cases, the resulting state is the same&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;span style=&quot;line-height: 14.4px;&quot;&gt;Any incoming messages are held (stashed) until recovery completion&lt;/span&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;line-height: 1.295; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;There is, of course, also an API for an actor to save snapshots of its current state, and receive a snapshot during recovery. The framework does not enforce you any rules for when and how to write snapshots, it only provides an API:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;override def &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;receive: &lt;/span&gt;&lt;span style=&quot;background-color: white; color: #20999d; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Receive &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;= {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;cmd: Command =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;persist(Event.&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(cmd)) { ev =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// change the state now that the event is persisted&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;state &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;background-color: white; color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.process(ev)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;if &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(SnapshotHelper.&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;isTimeToSnapshot&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// trigger a snapshot write&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;self &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;! SaveSnapshot&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; line-height: 1.2; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; line-height: 1.2; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;SaveSnapshot =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;saveSnapshot(&lt;/span&gt;&lt;span style=&quot;background-color: white; color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;SaveSnapshotSuccess&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(metadata) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// retain only the latest snapshot to ease up the database&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;val &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;criteria = &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;SnapshotSelectionCriteria&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(maxSequenceNr = metadata.sequenceNr - &lt;/span&gt;&lt;span style=&quot;background-color: white; color: blue; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; line-height: 1.2; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;deleteSnapshots(criteria)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;SaveSnapshotFailure&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(metadata, reason) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// not fatal - just log an error&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; line-height: 1.2; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.295; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Note that you can also maintain a journal of commands (in addition to saving events), but this is optional – it can be useful for getting a sense of how the system is used, and for debugging or testing.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;The snapshot store can be backed by a selection of data stores, and there is a number of community plugins.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
Persistence Query&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Akka Persistence Query is what implements the query side of CQRS. The API provides a stream of journaled events (an Akka Streams stream). The data stream is transformed and redirected to the query store for querying later.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Note that there still is a single system of record - the event log. Query stores can be deleted and re-populated at any time with no data loss.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-eff1c4f6-1435-9dbe-3267-532a67621431&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;img height=&quot;340px;&quot; src=&quot;https://lh3.googleusercontent.com/JVI1I080en5E0WvUTMY08Gb6cocTmG9-EaxVnYKEQFrVv4FCQ-ZI8DviobrYbxNaTwhQAnun_ASvmrYsyTt_IVaV-9_VCXZPHSERy8T-ucSX2Y0hOCyzAY9z0ZF5xQURZJt1QtLz_EY&quot; width=&quot;622px;&quot; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Note here that the same event journal can be projected to several query stores, and several event journals can be projected to the same query store.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Let&#39;s consider a practical example. We want to be able to query an audit trail of all modifications done to our system. The easiest way is to stream all events to an Elasticsearch index, so that the index could later be queried using Kibana.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Note that Elasticsearch may reject or lose writes (due to e.g. field mapping conflicts or network partitioning), but these&amp;nbsp;durability issues do not mean we should avoid using it – just don’t use it as a&amp;nbsp;primary DB, and have the index rebuilt in case of its corruption. A perfect task for Akka Persistence Query, which is going to facilitate the projection of our events to Elasticsearch.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Akka Persistence Query itself is not the query side of an application (it does not serve queries) – it is merely a transport facilitating migration of events from the write store (Cassandra in our case) to the actual query store (Elasticsearch in our case).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Read journal implementations typically have an API to provide a typed stream of events, which can then be transformed by Akka Streams combinators (to e.g. publish events to the query store).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;Let’s examine a complete example of an event publisher to Elasticsearch. The publisher uses Akka Persistence Query to evoke an Akka Streams stream of events from many event logs, but it also is a PersistentActor itself because it needs to implement a resumable projection (memorize the last event published to start where it has left off the last time).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;class &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Publisher &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;PersistentActor {&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// memorize the last offset written&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;: Option[UUID] = None&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;def &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;engageStreaming = {&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// by default the stream will terminate upon all exceptions&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;val &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;readJournal = PersistenceQuery(&lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.system)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// obtain a read journal&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.readJournalFor[scaladsl.CassandraReadJournal](&lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;cassandra-query-journal&quot;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// start streaming from the last offset written&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;val &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;initialUuid = &lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.getOrElse(readJournal.&lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;firstOffset&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// events to be published have to be tagged with &quot;publish_me&quot;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;// using an Event Adapter during the write flow&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; line-height: 1.2; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;// eventsByTag get you an endless stream of typed events.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;readJournal.eventsByTag(&lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;publish_me&quot;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;, initialUuid)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// use Akka Streams combinator to publish 4 events in parallel&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.mapAsync(&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;) { envelope =&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// the write to Elasticsearch has to be idempotent,&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// because a failed publishing attempt might be re-run.&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// achieve this by generating a stable id for this event&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;val &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;id = &lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;s&quot;&lt;/span&gt;&lt;span style=&quot;color: #00b8bb; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;{envelope.persistenceId}&lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #00b8bb; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;{envelope.sequenceNr}&lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;val &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;elasticFuture = envelope.event &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;match &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;e: Event =&amp;gt; &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Future &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// asynchronously write event e to Elasticsearch under id&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;ElasticSearchWriter.write(e, id)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// once the event is written, map to its offset&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;elasticFuture.map(_ =&amp;gt; envelope.offset)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.mapAsync(&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;) { offset =&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// persist the &#39;last offset written&#39; prior to moving forward,&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// handled by receiveCommand as in a typical PersistentActor.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; line-height: 1.2; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// note that the ask pattern is of type Future[Any]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;self &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;SetLastOffsetWritten&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(offset)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.runWith(Sink.&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;ignore&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.recover { &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;e =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// handle error by shutting the actor down&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;context.stop(self)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;}&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;br class=&quot;kix-line-break&quot; /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;
&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;A few words regarding the publisher code above:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;
&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;li&gt;The publisher actor is a Persistent Actor itself - it memorizes the events that have already been streamed to and acknowledged by Elasticsearch, and does not stream them again (a resumable projection).&lt;/li&gt;
&lt;li&gt;In case the publisher crashes with some events being in flight to/from Elasticsearch, those events would be re-sent after recovery. However, Elasticsearch document IDs are based on event sequence numbers that are stable and unique for each event, so the processing at Elasticsearch is effectively idempotent.&lt;/li&gt;
&lt;li&gt;This means that events are delivered to Elasticsearch in&amp;nbsp;effectively&amp;nbsp;an exactly-once manner.&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot;&gt;
&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Note that not all journals support the &lt;b&gt;eventsByTag &lt;/b&gt;call – without it, it is much more difficult to implement a resumable projection (although not impossible). For example, Cassandra journal 2.x does not support it, while Cassandra 3.x does.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-0c431376-1443-41aa-dd5a-3c0ddd442c47&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Basically you can have as many different materialized projections as you want, and all of them can use different data models and different db engines. Most systems actually need to have more than one read model to work well.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;You can even project a projection if you so choose.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;As was mentioned above, an important note is that Read consistency is eventual. It takes a little while (seconds) for persisted events to get into the projected stream. Most of the time, queries can tolerate that, but not always. Where consistency is important, use the actor in-memory state to serve simple queries (for example, “check email and bind it to account if it is available”)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
At least once message delivery&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Standard Akka provides the following guarantees:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;
&lt;li&gt;message delivery guarantee: at-most-once&amp;nbsp;&lt;/li&gt;
&lt;li&gt;ordering guarantees: peer to peer&amp;nbsp;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Imagine that at the moment of an application crash, your actor was waiting for a response to a message it has sent to another actor earlier. During recovery, both actors would get caught up to their current state, but the request would not automatically be re-sent, and the sending actor would be waiting for a response that would never arrive.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;Akka Persistence offers reliable message delivery API via the AtLeastOnceDelivery interface that takes care of re-sending messages when they have not been confirmed within a timeout.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;The key concept here is that the sender persists the following facts (in form of events, of course):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;
&lt;li&gt;message has been sent to recipient&lt;/li&gt;
&lt;li&gt;message has been acknowledged by the recipient&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;During actor startup (e.g. after a crash), the framework will prompt the persistent actor to re-send any &quot;sent&quot; yet &quot;non-acknowledged&quot; messages.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;A few words about the communication protocol:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;
&lt;li&gt;The recipient has to send message acknowledgements.&lt;/li&gt;
&lt;li&gt;The recipient has to:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;process messages in an idempotent manner, or&lt;/li&gt;
&lt;li&gt;have facilities to detect and handle duplicate messages&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Message ordering is no longer guaranteed due to re-transmissions&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
An example system&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Depicted below is an architecture taking advantage of most of things discussed so far.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span id=&quot;docs-internal-guid-eff1c515-1454-0061-4532-6668152ec54e&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;img height=&quot;393px;&quot; src=&quot;https://lh3.googleusercontent.com/943tSpVLHsR5VKVFGApyUJifA7eHJTkeyIojU67iKlSnh92C0fLhAuYmoInvhT2e8lKdEg8Z_f4cPNt6hPomkN4mOyLbzNM9of4N2TSEwzg6C4JVNiDhgH68pMgYAof9IRb_Ve2hDyY&quot; width=&quot;530px;&quot; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Write journals are backed by Cassandra, as it is a data store optimized for writes.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;A query store is backed by Elasticsearch, which gets populated by events from several event journals by means of Akka Persistence Queries.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;
&lt;li&gt;Event log projection to Elasticsearch is resumable - the publisher memorizes the &quot;last published&quot; position within the events stream using Akka Persistence.&lt;/li&gt;
&lt;li&gt;Message delivery to Elasticsearch is &quot;exactly-once&quot; due to stable document IDs and idempotent processing of them at Elasticsearch.&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&amp;nbsp;There are two read models:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;
&lt;li&gt;Simple queries requiring a consistent view of the state are served by actors themselves from their in-memory state.&lt;/li&gt;
&lt;li&gt;Complex queries (requiring data aggregation) tolerant to relaxed consistency are served by Elasticsearch.&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ol&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;The in-memory state can be considered a simple form of a read store. This architecture is called MemoryImage, in which the current state is kept in and queried from main memory. Naturally, your current state has to fit into memory.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;The benefits of an in-memory image are as follows:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;
&lt;li&gt;you don’t need to keep the application state in an up-to-date persistent store, and keep them in sync&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;in case of an application crash, the in-memory state gets restored from the journal&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;you get high performance, since queries are served from in-memory state with no IO or remote calls to database systems&lt;/li&gt;
&lt;li&gt;you get rid of database mapping code&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;h4&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
Failures&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;A persistent actor gets unconditionally stopped in case:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;
&lt;li&gt;persistence of an event fails&lt;/li&gt;
&lt;li&gt;state recovery during actor startup fails&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;This is done in order to to avoid data inconsistency occurring.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;This means that Akka supervision hierarchy you are familiar with no longer works as expected - the actor has to be restarted not only after a crash, but also after a stop.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;Additionally, in case the problem lies in database connectivity, it would be reasonable to wait for a bit prior to re-creating the actor (and retrying recovery) to avoid the &quot;thundering herd&quot; problem.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;In order to handle all of the above, consider the following explicit supervisor:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: white; font-family: &#39;Courier New&#39;; font-size: 9pt;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;color: grey; font-style: italic;&quot;&gt;// restart child actors on all kinds of java.lang.Throwable, not just non-fatal kinds of java.lang.Exception&lt;/span&gt;&lt;span style=&quot;color: navy; font-weight: bold;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style=&quot;background-color: white; font-family: &#39;Courier New&#39;; font-size: 9pt;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;color: navy; font-size: 9pt; font-weight: bold;&quot;&gt;def &lt;/span&gt;&lt;span style=&quot;font-size: 9pt;&quot;&gt;supervisorStrategy = &lt;/span&gt;&lt;span style=&quot;font-size: 9pt; font-style: italic;&quot;&gt;OneForOneStrategy&lt;/span&gt;&lt;span style=&quot;font-size: 9pt;&quot;&gt;()(SupervisorStrategy.&lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-size: 9pt; font-style: italic;&quot;&gt;defaultDecider&lt;/span&gt;&lt;span style=&quot;font-size: 9pt;&quot;&gt;.orElse {&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style=&quot;background-color: white; font-family: &#39;Courier New&#39;; font-size: 9pt;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;  &lt;span style=&quot;color: navy; font-weight: bold;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;NonFatal&lt;/span&gt;(_) =&amp;gt; SupervisorStrategy.Restart
})&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style=&quot;background-color: white; font-family: &#39;Courier New&#39;; font-size: 9pt;&quot;&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;pre style=&quot;background-color: white; font-family: &#39;Courier New&#39;; font-size: 9pt;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;color: navy; font-weight: bold;&quot;&gt;val &lt;/span&gt;backoffSupervisorProps = BackoffSupervisor.&lt;span style=&quot;font-style: italic;&quot;&gt;props&lt;/span&gt;(
  Backoff.&lt;span style=&quot;font-style: italic;&quot;&gt;&lt;b&gt;onStop&lt;/b&gt;&lt;/span&gt;(
    actorProps, &lt;span style=&quot;font-size: 9pt; font-style: italic;&quot;&gt;// your wrapped (supervised) actor props&lt;/span&gt;
    childName = actorName + &lt;span style=&quot;color: green; font-weight: bold;&quot;&gt;&quot;Supervised&quot;&lt;/span&gt;,
    minBackoff = &lt;span style=&quot;color: blue;&quot;&gt;3&lt;/span&gt;.seconds,
    maxBackoff = &lt;span style=&quot;color: blue;&quot;&gt;10&lt;/span&gt;.seconds,
    randomFactor = &lt;span style=&quot;color: blue;&quot;&gt;0.2&lt;/span&gt;)
    .&lt;b&gt;withSupervisorStrategy&lt;/b&gt;(supervisorStrategy))

&lt;span style=&quot;color: #660e7a; font-style: italic;&quot;&gt;context&lt;/span&gt;.actorOf(backoffSupervisorProps, actorName)&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;div style=&quot;background-color: white;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: white;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: normal;&quot;&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;Created&lt;/span&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;&amp;nbsp;&lt;/span&gt;this way, an actor would get restarted according to the specified supervision strategy after a crash, and it would also get restarted after having been stopped by the Akka Persistence framework, after a backoff period.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-size: large; font-weight: normal; vertical-align: baseline;&quot;&gt;Serialization&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;By default, Java serialization is used by Akka Persistence when storing your events. This is not advised mainly because it does not handle schema evolution well (and it is rumored to be quite slow). It’s best to serialize events as generic data structures such as maps and lists, with as little class information as possible.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;We serialize our events to JSON because:&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;JSON makes it easier to handle schema evolution. For example, removing fields or adding fields that have a default value is basically free. &lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;it&#39;s human-readable (easier to debug) &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;we use the same serialization engine for both persisting events to Cassandra and publishing events to Elasticsearch &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;no vendor lock-in (unlike Kryo or Scala Pickling)&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li dir=&quot;ltr&quot; style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;using spray-json + spray-json-shapeless allows to have a minimum of boilerplate code (no schema needed, a lot of built-in support for scala types, whole type hierarchies automatically get serialized by the json-shapeless library)&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;However there is a price to pay: performance. For example, JSON serialization is a major CPU consumer during recovery:&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;img height=&quot;188&quot; src=&quot;https://lh5.googleusercontent.com/Kue4KfEOWQ4LMBlosj-C0TO5YEJ2xFVqw5YAwFo7YEJCh02Ug1ZkgTs0C-tVQO8tnMMIPvgVoC_zzRBjj3Tw5JoT64Wwiy9V_DkNZVojhb49OQd4UbkeSG-tvYQsKL5yHaxJSVUb&quot; style=&quot;-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);&quot; width=&quot;624&quot; /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;line-height: 1.38;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-1424-7a5c-c6bd-428cdc27451d&quot; style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;When serializing your state for snapshots, Java serialization is also used by default. Here it might be reasonable to just use the fastest serialization available, because in case the&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: transparent; line-height: 22.08px; white-space: pre-wrap;&quot;&gt;types of your internal &lt;/span&gt;&lt;span style=&quot;line-height: 1.38;&quot;&gt;&lt;span style=&quot;background-color: transparent; color: black; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;state change, the snapshot could be simply dropped and rebuilt from events by replaying the whole stream again.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;Persistent FSM&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;In case you wish your persistent actors to process commands in a FSM like fashion, Akka provides the PersistentFSM API.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;line-height: 20.24px; white-space: pre-wrap;&quot;&gt;Consider an actor representing a digital lock that can be unlocked by entering a combination of digits. The lock accepts the following commands (not persisted):&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;color: black; font-family: &amp;quot;times new roman&amp;quot;; font-size: small; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: &#39;Times New Roman&#39;; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;b id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;sealed trait &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Command&lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit; line-height: 1.554;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case object &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Lock &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Command&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit; line-height: 1.554;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case class &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;EnterDigit(digit: Digit) &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Command&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case object &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;TryUnlock &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Command&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;The lock can be in one of the following states (persisted):&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;sealed trait LockState extends FSMState&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;display: inline !important; margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case object Locked extends LockState {&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;display: inline !important; margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; override def identifier: &lt;/span&gt;&lt;span style=&quot;color: #20999d; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;String &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;Locked&quot;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;display: inline !important; margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;display: inline !important; margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case object Unlocked extends LockState {&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;display: inline !important; margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; override def identifier: &lt;/span&gt;&lt;span style=&quot;color: #20999d; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;String &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;= &quot;Unlocked&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; line-height: 1.554; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;Any actions performed with the lock are recorded as a sequence of &quot;domain events&quot;, which are persisted. Those events are replayed on an actor&#39;s startup in order to restore the latest state:&lt;/span&gt;&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// note the past tense&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;sealed trait &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;DomainEvent&lt;/span&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;display: inline !important; margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case object &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;ComboCleared &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;DomainEvent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case class &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;DigitEntered(digit: Digit) &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;DomainEvent&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case class &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;IntrusionDetected(data: &lt;/span&gt;&lt;span style=&quot;color: #20999d; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Seq&lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;[Digit]) &lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;extends &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;DomainEvent&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;The lock state represents the sequence of currently entered digits (not persisted, reconstructed on recovery):&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #20999d; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Seq&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;[Digit]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;The following DSL binds everything up into an FSM:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;startWith(Unlocked, &lt;/span&gt;&lt;span style=&quot;background-color: white; color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Seq&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;())&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;when(Unlocked) {&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Event&lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(Lock, _) ⇒&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// persist only the state&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;goto(Locked) andThen {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// perform a side effect&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;_ =&amp;gt; &lt;/span&gt;&lt;span style=&quot;color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;reportActor &lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;! &lt;/span&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;the lock is secure&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;display: inline !important; line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;when(Locked) {&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Event&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;EnterDigit&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(digit), currentCombo) ⇒&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// persist the Selected event only&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;stay applying &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;DigitEntered&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(digit)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Event&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(TryUnlock, currentCombo) ⇒&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;if &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(currentCombo == &lt;/span&gt;&lt;span style=&quot;background-color: white; color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;SECRET_COMBO&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;goto(Unlocked) applying ComboCleared replying &lt;/span&gt;&lt;span style=&quot;background-color: white; color: green; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;welcome to the realm&quot;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;} &lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;else &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// persist the Off event only&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;stay applying(ComboCleared, &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;IntrusionDetected&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(currentCombo))&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span id=&quot;docs-internal-guid-5aa82e7b-1499-808d-c826-fb46de92af68&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149c-5ef2-8168-9561350823df&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;The following function constructs the state data from events:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;override def &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;applyEvent(event: DomainEvent, stateBeforeEvent: &lt;/span&gt;&lt;span style=&quot;background-color: white; color: #20999d; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Seq&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;[Digit]): &lt;/span&gt;&lt;span style=&quot;background-color: white; color: #20999d; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Seq&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;[Digit] = {&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;  event &lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;match &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;   &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;ComboCleared =&amp;gt; &lt;/span&gt;&lt;span style=&quot;background-color: white; color: #660e7a; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Seq&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;()&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;   &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;DigitEntered&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(digit: Digit) =&amp;gt; stateBeforeEvent :+ digit&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;   &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; color: navy; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;case &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;IntrusionDetected&lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(_) =&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.554; margin-bottom: 8pt; margin-top: 0pt;&quot;&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;   &amp;nbsp;&amp;nbsp;&amp;nbsp;stateBeforeEvent &lt;/span&gt;&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;// persist for audit purposes only&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; line-height: 1.554; white-space: pre-wrap;&quot;&gt;  }&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;; font-size: 12px; line-height: 1.554; white-space: pre-wrap;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span style=&quot;font-size: 14.6667px; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 20.24px; white-space: pre-wrap;&quot;&gt;During recovery, the actor state is recovered automatically, and state data is recovered by repeatedly calling the applyEvent function above for each event persisted.&lt;/span&gt;&lt;span style=&quot;line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;We’ve experienced issues with the API though:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;Built-in state forMax() &amp;nbsp;timers have a bug (#19688) - they work incorrectly on recovery. Use explicit timers as a work-around.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;We have not found a way to use snapshots for FSM, so FSM actors should not have long journals.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;No built-in analogue for the ‘at least once delivery guarantee’ kind of API discussed above&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;No support for transient states (e.g. states to which you don’t want to recover).&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal; line-height: 20.24px; white-space: pre-wrap;&quot;&gt;Persistent actor in a cluster&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; line-height: 20.24px; white-space: pre-wrap;&quot;&gt; A persistent actor must be a cluster singleton (unique persistenceId per cluster). At all times, only one actor should write events into a journal.
 If you have a cluster, but all your persistent actors fit into memory of the same machine, you can use the ClusterSingleton manager that would do its best to ensure there is only one instance of the persistent actor, located on the oldest node.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span id=&quot;docs-internal-guid-3a33b64d-152a-2a7a-2a4a-d5a51846130f&quot;&gt;&lt;span style=&quot;background-color: transparent; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;img alt=&quot;https://documents.lucidchart.com/documents/ebec7350-2d39-4c75-ae4b-55ac13bf6f6a/pages/0_0?a=126&amp;amp;x=138&amp;amp;y=161&amp;amp;w=924&amp;amp;h=418&amp;amp;store=1&amp;amp;accept=image%2F*&amp;amp;auth=LCA%201444f2f8110a54f6707c98fb07aba6572f09e7dd-ts%3D1458838848&quot; height=&quot;283&quot; src=&quot;https://lh4.googleusercontent.com/gzYNubPeTiHKqYPuvdUBGvNuS3tpHL1IF4othRJebdBG_pKMSaf8niQJhewmZqzapC0dE32qYJQe_gLmpy_ZkvxCNECUbZjI-gC5bjzBG6zpybeFn10AoX_0XRYnSA1_x5EZYqqmbWi5Liph6Q&quot; style=&quot;-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);&quot; width=&quot;624&quot; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 20.24px; white-space: pre-wrap;&quot;&gt;If your persistent actors do not fit onto the same JVM, you can use ClusterSharding manager to spread persistent actors evenly across the cluster.
&lt;/span&gt;&lt;span id=&quot;docs-internal-guid-3a33b64d-152a-41ea-e16d-2d98a345d386&quot;&gt;&lt;span style=&quot;background-color: transparent; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;img alt=&quot;https://documents.lucidchart.com/documents/ebec7350-2d39-4c75-ae4b-55ac13bf6f6a/pages/0_0?a=130&amp;amp;x=138&amp;amp;y=161&amp;amp;w=924&amp;amp;h=418&amp;amp;store=1&amp;amp;accept=image%2F*&amp;amp;auth=LCA%20c3c310b4d3f55dcf626b2584659087fa4396b11a-ts%3D1458838848&quot; height=&quot;283&quot; src=&quot;https://lh3.googleusercontent.com/g9b_4_turw9YfcoFTV-2b4l5StacpvXV_HfBkZpBKJ-0Di6oHRpLklUB50pJQDFlP8_4jzx6bpCnInDHDX8gaAaD5_p5HPXOnzF9p-PBkzTtkCGcmVEONZhrpmEcLQIUCDPTXSsClq4AtQo7Jw&quot; style=&quot;-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);&quot; width=&quot;624&quot; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h4&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: large; font-weight: normal;&quot;&gt;Performance considerations&lt;/span&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;An application using Akka Persistent actors has been tested on the following setup:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Storage (Journal/Snapshots): Cassandra 3.3 - m3.medium (AWS) - 3-node cluster&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Application: Akka 2.4.2, Play 2.4 - c4.large (AWS)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Total number of journaled events: ~1.7M (result of ~1.5 day under 200 req/sec load)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The table below depicts the effects of Akka Persistence on normal system functioning. In short, event persistence has little impact, but the more often snapshots are written, the higher the resource consumption:&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre style=&quot;background-color: white;&quot;&gt;&lt;pre style=&quot;background-color: white;&quot;&gt;&lt;pre style=&quot;background-color: white;&quot;&gt;&lt;span id=&quot;docs-internal-guid-5aa82e7b-149e-b6b3-d686-789e8a650845&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;font-weight: bold; margin-left: 0pt;&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; border: none;&quot;&gt;&lt;colgroup&gt;&lt;col width=&quot;188&quot;&gt;&lt;/col&gt;&lt;col width=&quot;114&quot;&gt;&lt;/col&gt;&lt;col width=&quot;162&quot;&gt;&lt;/col&gt;&lt;col width=&quot;129&quot;&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;CPU, %&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Transmit, KB/s&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Avg GC pause, ms&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Nothing gets persisted&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;79&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;185&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;3..4&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Events get persisted, but no snapshots&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;79&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;195&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;6&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Snapshots every 10K events&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;~81&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;200&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;5&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Snapshots every 200 events&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;~84&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;320&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;8&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;b style=&quot;font-weight: normal;&quot;&gt;
&lt;/b&gt;&lt;/span&gt;&lt;div dir=&quot;ltr&quot; style=&quot;font-weight: bold; line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;The table below depicts the effects of Akka Persistence on actor recovery. In short, snapshot frequency directly translates to actor recovery time improvements:&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;b style=&quot;font-weight: normal;&quot;&gt;
&lt;/b&gt;&lt;/span&gt;&lt;div dir=&quot;ltr&quot; style=&quot;font-weight: bold; margin-left: 0pt;&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; border: none;&quot;&gt;&lt;colgroup&gt;&lt;col width=&quot;196&quot;&gt;&lt;/col&gt;&lt;col width=&quot;200&quot;&gt;&lt;/col&gt;&lt;col width=&quot;196&quot;&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Recovery time&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Total events recovered&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;No snapshots&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;5m 21s&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;1700K&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Every 10K events&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;36s&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;83K&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;height: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Every 200 events&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;11s&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;td style=&quot;border-bottom: solid #9e9e9e 1px; border-left: solid #9e9e9e 1px; border-right: solid #9e9e9e 1px; border-top: solid #9e9e9e 1px; padding: 11px 11px 11px 11px; vertical-align: top;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;line-height: 1.44; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;span style=&quot;background-color: white; color: black; font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;12K&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;
&lt;/span&gt;&lt;pre&gt;&lt;span style=&quot;font-family: &amp;quot;helvetica neue&amp;quot; , &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;To summarize: in our particular application, event persistence is lightweight, but snapshotting is not.
However, snapshots do significantly reduce recovery times.&lt;/span&gt;&lt;/pre&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/pre&gt;
&lt;/pre&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='https://blog.digital-magic.io/feeds/6376084686974194286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://blog.digital-magic.io/2016/04/practical-akka-persistence.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default/6376084686974194286'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8514295606932409163/posts/default/6376084686974194286'/><link rel='alternate' type='text/html' href='https://blog.digital-magic.io/2016/04/practical-akka-persistence.html' title='Practical Akka Persistence'/><author><name>Aleksei Irbe</name><uri>http://www.blogger.com/profile/14402596669774744614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh4.googleusercontent.com/OOV2fW9ituZhyRQot0Fv5XmqX8DgqPTzCZOsD-7cxvssMoiAOk2lBprFFhDCppW8kRglFoFjFTZitKRQI3VWqkjtdrLqkOHS9GDgSV5kWZtb6YtFqhg0-OzopUnZIaaSx-aWxyb1iFs_66OrYA=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry></feed>