<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>ostinelli|net</title><description>Roberto Ostinelli&apos;s blog.</description><link>https://www.ostinelli.net/</link><language>en-us</language><item><title>Simple Procedural Walk for UE4</title><link>https://www.ostinelli.net/simple-procedural-walk-for-ue4/</link><guid isPermaLink="true">https://www.ostinelli.net/simple-procedural-walk-for-ue4/</guid><description>In my spare time I love dedicating some energy to Unreal Engine 4. Today, I&apos;m releasing my first UE4 plugin, Simple Procedural Walk. I&apos;ve had an idea for a game for quite a while (on Steam, Subtype Grounds), which basically takes you in a cooperative journey to destroy the A.I. responsible for robots taking over the world. That&apos;s another story, but while I…</description><pubDate>Mon, 26 Apr 2021 08:13:00 GMT</pubDate><content:encoded>&lt;p&gt;In my spare time I love dedicating some energy to Unreal Engine 4. Today, I&apos;m releasing my first UE4 plugin, &lt;a href=&quot;https://www.unrealengine.com/marketplace/simple-procedural-walk&quot;&gt;Simple Procedural Walk&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;ve had an idea for a game for quite a while (on Steam, &lt;a href=&quot;https://store.steampowered.com/app/860020/Subtype_Grounds/&quot;&gt;Subtype Grounds&lt;/a&gt;), which basically takes you in a cooperative journey to destroy the A.I. responsible for robots taking over the world. That&apos;s another story, but while I was animating the killer robots for this game, I found out about how procedural animations can really help in making their movement realistic and interesting, so I decided to give that a try. But... What is procedural animation?&lt;/p&gt;

&lt;p&gt;&quot;Standard&quot; animations are generally the result of pre-saved animations, whether these are designed by hand with tools such as Blender, or recorded by using motion capture systems. These animations are then applied to your models and played back, bringing your characters to life.&lt;/p&gt;
&lt;p&gt;&quot;Procedural&quot; animations, on the contrary, are not pre-made or pre-recorded: everything is computed in real time based on the character position and their environment. This has numerous advantages. For instance in a walking cycle, the feet of your character will perfectly adapt to the terrain, and they will not slide in unexpected ways. They can even move apart to avoid holes in the ground, or look for places were they can properly get a foothold. The body can be moved so that it gets the proper inclination, and so on.&lt;/p&gt;
&lt;p&gt;These two techniques (pre-saved and procedural) are often combined, for instance a motion-captured human walking cycle might be coupled with procedural elements so that, for instance, the feet adapt to the terrain. This gives the advantage of a more natural, organic looking cycle, while supporting the character adaptation to their surroundings. However, pre-saved animations can only be modified up to a certain point while, on the other hand, procedural animations have their own limitations (for instance, it is difficult to achieve properly looking organic movements).&lt;/p&gt;
&lt;p&gt;For my robots, procedural animation is a perfect fit, since it is particularly good looking for robotic or insectoid creatures.&lt;/p&gt;
&lt;p&gt;Here&apos;s Simple Procedural Walk trailer video:&lt;/p&gt;
&lt;div class=&quot;video-embed&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/JLZa2ZsE3SE&quot; title=&quot;Embedded video&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;It is interesting to see how much control you can have on the movement itself with procedural animations.&lt;/p&gt;
&lt;p&gt;For example, it is possible to considerably change the overall feel of the movement by having the character unplant its feet at different times. This video demonstrates how a single parameter in the plugin can change the look of a walk cycle:&lt;/p&gt;
&lt;div class=&quot;video-embed&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/Lm2GpmVtZLg&quot; title=&quot;Embedded video&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;If you are interested, you may check Simple Procedural Walk out on the &lt;a href=&quot;https://www.unrealengine.com/marketplace/simple-procedural-walk&quot;&gt;Unreal Engine 4 marketplace&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>A journey to Syn v2, a better Erlang &amp; Elixir Process Registry and Group manager</title><link>https://www.ostinelli.net/a-journey-to-syn-v2/</link><guid isPermaLink="true">https://www.ostinelli.net/a-journey-to-syn-v2/</guid><description>For those who don&apos;t know it, Syn (short for synonym) is a global Process Registry and Process Group manager for Erlang and Elixir that I&apos;ve written a few years back. It has been around for some time now, and it has served me well on many occasions. Through the years, I&apos;ve built up a series of considerations and ideas for improvement, and now the time has…</description><pubDate>Mon, 18 Nov 2019 14:44:09 GMT</pubDate><content:encoded>&lt;p&gt;For those who don&apos;t know it, &lt;a href=&quot;https://github.com/ostinelli/syn&quot;&gt;Syn&lt;/a&gt; (short for &lt;em&gt;synonym&lt;/em&gt;) is a global Process Registry and Process Group manager for Erlang and Elixir that I&apos;ve written a few years back. It has been around for some time now, and it has served me well on many occasions. Through the years, I&apos;ve built up a series of considerations and ideas for improvement, and now the time has come to put all of these back into Syn.&lt;/p&gt;
&lt;p&gt;Syn v2 has been rewritten from the grounds up, and I&apos;d like to share the reasoning and the architectural choices behind this work. Since Syn is written in Erlang, the few portions of the code here below will show Erlang syntax. Don&apos;t let that discourage you if you are an Elixir developer though, as the same principles apply.&lt;/p&gt;

&lt;h2 id=&quot;the-analysis&quot;&gt;The analysis&lt;/h2&gt;
&lt;h3 id=&quot;things-i-wanted-to-keep&quot;&gt;Things I wanted to keep&lt;/h3&gt;
&lt;p&gt;I&apos;ve always treated a Process Registry as a specialized subset of a Key / Value store. Yes, the Key is the process registered name and the Value is the &lt;code&gt;pid()&lt;/code&gt;, but the important bit here is that a process inherently belongs to a node - because it &lt;em&gt;runs there&lt;/em&gt;. This changes the game quite significantly.&lt;/p&gt;
&lt;p&gt;Contrary to standard Key / Value stores where you &lt;em&gt;want&lt;/em&gt; to keep all of your data when a node leaves or crashes, why would you want to keep the name reference to a process, if that process runs on the node that left, or worse, crashed (and the process with it)? If a node gets added, why would you want to handoff a running process&apos; registration handling to this new node (so, &lt;em&gt;not&lt;/em&gt; the node the process is running on)? In general, why would you want to decouple the &lt;em&gt;node&lt;/em&gt; that handles the registered name of a process from the &lt;em&gt;process&lt;/em&gt; itself?&lt;/p&gt;
&lt;p&gt;If your answer is that in case of nodes leaving / crashing you need to keep the process&apos; information, then what you need is a persistent data storage, not a Process Registry. If your answer is that you want to &lt;em&gt;spawn&lt;/em&gt; and &lt;em&gt;load balance&lt;/em&gt; processes across a cluster (i.e. workers, that also happen to end up registered by name), then maybe what you need is a Job Queue, not necessarily a Process Registry.&lt;/p&gt;
&lt;p&gt;Now, if what you want from your Process Registry is to register &lt;em&gt;existing&lt;/em&gt; processes, then maybe you can agree that a &lt;em&gt;process&lt;/em&gt;&apos; registration is strongly tied to the &lt;em&gt;node&lt;/em&gt; the process runs on. If the node dies, then the process dies as well, and keeping its registration name around probably doesn&apos;t make much sense. If you agree to this, then my suggestion is that in a distributed registry every node should be handling the registration of the processes that run on it.&lt;/p&gt;
&lt;p&gt;In this scenario, we have ourselves a different paradigm from the ones of standard Key / Value stores. For instance, you do not need a Hash Ring to load balance the processes in your cluster and create replicas for fault tolerance of data: if a process or the node it runs on dies, you want to let its registration name go. You could still consider using a hash ring or consensus algorithms such as Raft to register a name, because you might experience race conditions for the same name being registered simultaneously on different nodes. However, Syn takes the approach of using a similar conflict resolution mechanism used to resolve net splits for these cases.&lt;/p&gt;
&lt;p&gt;This is even more true in the context where Syn was born. In &lt;a href=&quot;https://en.wikipedia.org/wiki/Internet_of_things&quot;&gt;IoT&lt;/a&gt; applications, you generally have a &lt;em&gt;process&lt;/em&gt; that handles an external (TCP/UDP) &lt;em&gt;socket&lt;/em&gt; to a physical &lt;em&gt;device&lt;/em&gt;. It only makes sense that the process runs on the same node of the socket it handles, because in this scenario (maybe it&apos;s just me) I cannot see the sense of having an external socket being managed by a process that runs on a different node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the node the socket runs on dies, you most probably want the process that handles it to die as well.&lt;/li&gt;
&lt;li&gt;Reciprocally, if the socket handler process dies, you&apos;d loose all of its state and you&apos;d probably would want to disconnect the device from the socket anyway.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To sum it up, I wanted to keep Syn v1 paradigm which is: every node is the &lt;em&gt;authority&lt;/em&gt; for registering the processes that run on it. Load balancing is not part of this Process Registry, and it rather has to do with whatever causes processes to be spawned in the first place (i.e. external sockets get created on a specific node based on TCP Load Balancing mechanisms).&lt;/p&gt;
&lt;p&gt;Finally, I wanted also to keep a full registry replica on every node of the cluster, so that Syn is optimized for read-intensive operations rather than write-intensive ones. This also seems to make sense, since if you do want to register a process by a name it&apos;s probably because you want it to live long enough for it to have an alias and keep track of it system-wide.&lt;/p&gt;
&lt;h3 id=&quot;things-i-wanted-to-improve&quot;&gt;Things I wanted to improve&lt;/h3&gt;
&lt;h4 id=&quot;1-dynamic-node-membership&quot;&gt;1. Dynamic node membership&lt;/h4&gt;
&lt;p&gt;Contrary to what some forum users seem to think, Syn v1 does manage dynamic node addition pretty well. The only caveat is that Syn v1 needs to be initialized on a node &lt;em&gt;after&lt;/em&gt; a node joins a cluster: your application needs to have the logic to connect to the other nodes, and only then issue a call to &lt;code&gt;syn:init/0&lt;/code&gt; which initializes the mnesia tables on the node. This is because Syn v1 uses mnesia&apos;s replication features, and mnesia enforces a specific instructions&apos; order when creating / adding a node to existing replicated tables.&lt;/p&gt;
&lt;p&gt;For instance, the call to &lt;a href=&quot;http://erlang.org/doc/man/mnesia.html#change_config-2&quot;&gt;mnesia:change_config/2&lt;/a&gt; to configure &lt;code&gt;extra_db_nodes&lt;/code&gt; needs to happen before the creation of a table (via &lt;a href=&quot;http://erlang.org/doc/man/mnesia.html#create_table-2&quot;&gt;mnesia:create_table/2&lt;/a&gt;) or the addition of a node to existing replicated tables (via &lt;a href=&quot;http://erlang.org/doc/man/mnesia.html#add_table_copy-3&quot;&gt;mnesia:add_table_copy/3&lt;/a&gt;). If you&apos;re curious about this process, you can head to &lt;a href=&quot;https://github.com/ostinelli/syn/blob/1.6.3/src/syn_backbone.erl#L43&quot;&gt;syn_backbone.erl&lt;/a&gt; where you can get the gist on how Syn v1 sets up dynamic replication via mnesia.&lt;/p&gt;
&lt;p&gt;This &lt;em&gt;could&lt;/em&gt; also potentially lead to a rare race condition, which BTW never happened to me in all of these years. If two nodes of a cluster were to be started during a net split so that they do not see each other on boot, they would initialize mnesia separately which would result in them having their own version of Syn tables, with their own fingerprint, that cannot be merged afterwards (due to mnesia internals).&lt;/p&gt;
&lt;p&gt;Finally, while mnesia does support node addition, it does not as easily support node removal. The equivalent command to remove a table copy, &lt;a href=&quot;http://erlang.org/doc/man/mnesia.html#del_table_copy-2&quot;&gt;mnesia:del_table_copy/2&lt;/a&gt;, has some other caveats (for example it requires mnesia to be stopped). It is certainly doable though, but the question here would be &lt;em&gt;when&lt;/em&gt; to do it in an automated way. For instance, a node could get notified that another node left the cluster, but should it then remove the missing node&apos;s table copy? To do that, it would first have to stop mnesia - and lose all of the ram data - and then, what if the other node was simply down due to a temporary network failure that caused a net split? For these reasons, node removal was never implemented in Syn v1. If a node left, the local mnesia tables would still have it included in &lt;code&gt;extra_db_nodes&lt;/code&gt; that mnesia uses for replication, which is not a big deal.&lt;/p&gt;
&lt;p&gt;Therefore, even if Syn v1 does support dynamic node addition, there are these caveats to keep in mind - and I can see why some users might have misinterpreted them.&lt;/p&gt;
&lt;h4 id=&quot;2-net-splits&quot;&gt;2. Net Splits&lt;/h4&gt;
&lt;p&gt;Even though these events are rare, they do happen. Moreover, I felt that a mechanism that would solve those would also basically implement a fully working dynamic addition / removal of nodes.&lt;/p&gt;
&lt;p&gt;Mnesia does not handle net splits very well. To give some support to this issue, Ulf Wiger experimented and created his &lt;a href=&quot;https://github.com/uwiger/unsplit&quot;&gt;unsplit&lt;/a&gt; framework (he talks about it in &lt;a href=&quot;http://erlang.org/pipermail/erlang-questions/2010-February/049213.html&quot;&gt;this post&lt;/a&gt; on the Erlang questions mailing list). However, I&apos;ve had mixed results with the mechanism that he uses in there.&lt;/p&gt;
&lt;p&gt;Basically, Ulf&apos;s solution works by first subscribing to mnesia events. If mnesia triggers an &lt;em&gt;inconsistent database&lt;/em&gt; event for a remote node (so it is running a partitioned network), the unsplit code will check whether &lt;a href=&quot;https://github.com/uwiger/unsplit/blob/8ab6130e6c8ef167e82f6b25f875b2bb293a1345/src/unsplit_server.erl#L143&quot;&gt;the remote node is already part of mnesia&apos;s local running nodes&lt;/a&gt;. If it is not, it will manually connect the local to the remote node using the undocumented &lt;a href=&quot;https://github.com/uwiger/unsplit/blob/8ab6130e6c8ef167e82f6b25f875b2bb293a1345/src/unsplit_server.erl#L163&quot;&gt;mnesia_monitor:connect_nodes/1&lt;/a&gt; method; while doing so, it will inject some custom resolution code that performs dirty read &amp;amp; write operations to the local and to the remote node&apos;s mnesia tables. I took this mechanism and made a specialized and simplified version for Syn v1, and if you&apos;re up for it you can check this implementation in &lt;a href=&quot;https://github.com/ostinelli/syn/blob/1.6.3/src/syn_consistency.erl&quot;&gt;syn_consistency.erl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While it works nicely in a 2 nodes cluster, I have unfortunately encountered an inconsistent behavior in bigger clusters. In a cluster of 3 nodes I would see the inconsistent database events triggered correctly by mnesia, but unfortunately mnesia would randomly consider the remote node that triggered the event as already part of its local running nodes. Thus, the resolution part of the code that would perform the read &amp;amp; write operations and solve the split brain situation wouldn&apos;t get a chance to run. My hunch is that mnesia is able to reconnect to parted nodes in a way that may happen before all of this mechanism gets the chance to be called, especially in partial net splits scenarios. I&apos;ve also tried forcing the resolution code to run without the checks, but I got the error &lt;code&gt;not_merged&lt;/code&gt; as the result of the merge fun in &lt;code&gt;mnesia_controller:connect_nodes/1&lt;/code&gt;, more precisely &lt;a href=&quot;https://github.com/ostinelli/syn/blob/1.6.3/src/syn_consistency.erl#L230&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I don&apos;t know whether this incapacity of randomly solving net splits in bigger clusters results from using mnesia&apos;s in a non-intended way by taking advantage of Ulf&apos;s mechanism (it seems that Ulf wanted to &lt;a href=&quot;https://github.com/uwiger/unsplit/issues/2&quot;&gt;test it with more than 2 nodes&lt;/a&gt; himself), or if I might have missed something in my implementation version. That said, handling net splits is not an immediate task especially if you&apos;re using a library that is not meant to do so. The feeling is that mnesia replication mechanisms are not intended to handle them, and hacking your way through might have unexpected results.&lt;/p&gt;
&lt;h4 id=&quot;3-behavior-and-customization&quot;&gt;3. Behavior and customization&lt;/h4&gt;
&lt;p&gt;Syn v1 allows to register a process with one name at a time, a behavior consistent with Erlang&apos;s global module. However, I felt this as a limitation and I wanted to allow multi-aliases process registration.&lt;/p&gt;
&lt;p&gt;Also, I wanted a more clean approach to support customization callbacks, i.e. a single callback module with its &lt;code&gt;syn_event_handler&lt;/code&gt; behavior that would be triggered depending on a developer&apos;s choices.&lt;/p&gt;
&lt;p&gt;Finally, in case of registry conflicts during a net split resolution (i.e. when two processes have registered the same name on different nodes during the net split), Syn v1 decides which process to keep and which one to discard. I wanted to provide developers with the ability of defining their own conflict resolution method. The developers could, for instance, save vector clocks data into the meta data of each process and use those to choose which process to keep in case of conflict.&lt;/p&gt;
&lt;h2 id=&quot;the-rewrite&quot;&gt;The rewrite&lt;/h2&gt;
&lt;p&gt;Given all of the above, the choices were simple and clear - and so the implementation.&lt;/p&gt;
&lt;h4 id=&quot;generic-register--unregister-operations-flow&quot;&gt;Generic Register / Unregister operations&apos; flow&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;When a registration request comes in for a Name and Pid, this request is routed to the node that the Pid is running on. In most cases, a registration request will be done from a process itself, which means that communication stays on the same node.&lt;/li&gt;
&lt;li&gt;Every registration request is treated by a single (gen server) process (the &lt;em&gt;registry process&lt;/em&gt;) on every node. This registry process starts monitoring the newly registered process, and also guarantees that registration / unregistration requests are necessarily consistent - since there&apos;s a per-node single registry process authority that sequentially treats them.&lt;/li&gt;
&lt;li&gt;The registry process writes to a local (not replicated) mnesia table (&lt;strong&gt;Edit in v2.1&lt;/strong&gt;) local ETS tables the Name and related Pid. This is an in-memory only table that gets created on application start and killed on application stop. I still use mnesia only because of its secondary index feature, as I need to be able to search for table entries both by Name and by Pid.&lt;/li&gt;
&lt;li&gt;The registry process then sends the registration / unregistration information to all of the other nodes in the cluster. This is not done by sending a message to the registry processes of the other nodes, rather it issues a remote procedure call (RPC) that directly writes in the local ETS tables of the remote nodes. This allows the other registry processes to be free from all intra-nodes syncing operations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Edit in v2.0.1&lt;/strong&gt; ---&amp;gt;&lt;/li&gt;
&lt;li&gt;When a node receives a registration information from another node, it checks locally whether there&apos;s a name conflict. If one is found, the node will try to gain a global lock for the conflicting name to run a specific portion of code that merges the conflicting data, since other registry processes might see this conflict as well.&lt;/li&gt;
&lt;li&gt;The registry process that succeeds in gaining the lock will compare the received registration data and will resolve the conflict between itself and the node that sent the registration information.&lt;/li&gt;
&lt;li&gt;Once done, the registry process will free the lock, and all the other nodes that eventually experienced the same name conflict will resolve the same conflict.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;nodes-addition&quot;&gt;Nodes&apos; addition&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;When a node joins a cluster, all the registry processes of the nodes in the cluster receive a NODE UP event for that node. Simultaneously, the joining node&apos;s registry process receives a NODE UP event for &lt;em&gt;all&lt;/em&gt; of the existing nodes in the cluster.&lt;/li&gt;
&lt;li&gt;Every registry process that receives a NODE UP event for a remote node will try to gain a global lock to run a specific portion of code that deals with merging remote data.&lt;/li&gt;
&lt;li&gt;The registry process that succeeds in gaining the lock will issue a RPC on the remote node and request the registry data for all of the processes that run on it, for which the remote node is the authority. It will then write this information on its local ETS tables. If this happens after a net split, some naming conflicts might happen at this moment, and a choice on which process to keep will be made depending on the specified logic. By default, Syn will keep the local process, kill the remote process and remove the latter from the ETS tables on the remote node (via a RPC).&lt;/li&gt;
&lt;li&gt;Once done, the registry process will free the lock. It will not send its data, as it will be requested from the other registry processes when they get their turn to grab the lock.&lt;/li&gt;
&lt;li&gt;The code for all of this at the time of writing can be seen &lt;a href=&quot;https://github.com/ostinelli/syn/blob/2.0.0-rc.1/src/syn_registry.erl#L242&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;nodes-removal&quot;&gt;Nodes&apos; removal&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;When a node leaves a cluster (voluntarily, because it crashed or because of a net split), all the registry processes of the nodes in the cluster receive a NODE DOWN event for that node.&lt;/li&gt;
&lt;li&gt;The registry processes that receive this event proceed to remove from their local mnesia tables all of the processes that ran on the disconnected node.&lt;/li&gt;
&lt;li&gt;This works well also in context of partial net splits (&lt;code&gt;A &amp;lt;--&amp;gt; B &amp;lt;--&amp;gt; C&lt;/code&gt; where node A can see B, B can see A and C, and C can only see B), since every node keeps locally only the information of the nodes it can see.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;
&lt;p&gt;These are the results of the rewrite.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Addition &amp;amp; removal of nodes in a cluster is done in a completely dynamic and transparent way, with no caveats.&lt;/li&gt;
&lt;li&gt;Automated repairing from net splits has now been taken to a new level. You can check the &lt;a href=&quot;https://github.com/ostinelli/syn/tree/2.0.0-rc.1/test&quot;&gt;existing test suites&lt;/a&gt; to see what is being covered.&lt;/li&gt;
&lt;li&gt;Finally, there now is a single callback module with the &lt;code&gt;syn_event_handler&lt;/code&gt; behavior, and the ability for the developer to use a custom function to resolve naming conflicts after net splits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There still might be corner cases that I haven&apos;t considered in terms of consistency, if some arise I will do my best to tackle any of those in future improvements of Syn.&lt;/p&gt;
&lt;p&gt;You can grab your copy of Syn v2 on &lt;a href=&quot;https://hex.pm/packages/syn&quot;&gt;Hex&lt;/a&gt; or &lt;a href=&quot;https://github.com/ostinelli/syn/&quot;&gt;Github&lt;/a&gt;. Happy registering!&lt;/p&gt;
</content:encoded></item><item><title>Modern Erlang for Beginners: my course</title><link>https://www.ostinelli.net/modern-erlang-for-beginners/</link><guid isPermaLink="true">https://www.ostinelli.net/modern-erlang-for-beginners/</guid><description>I remember when I first started learning Erlang, many years ago. There was the fundamental Programming Erlang book by the late Joe Armstrong, the official Erlang documentation, some various books but what really helped me was a screencast from Kevin Smith sold on the Pragmatic Bookshelf&apos;s website. I am a visual learner, which means that it is much easier for…</description><pubDate>Wed, 13 Mar 2019 20:14:00 GMT</pubDate><content:encoded>&lt;p&gt;I remember when I first started learning Erlang, many years ago. There was the fundamental Programming Erlang book by the late Joe Armstrong, the official Erlang documentation, some various books but what really helped me was a screencast from Kevin Smith sold on the Pragmatic Bookshelf&apos;s website.&lt;/p&gt;
&lt;p&gt;I am a visual learner, which means that it is much easier for me to learn with videos or by pairing with other people. So, after those years I decided that I wanted to add my little contribution to the Erlang courses that available out there.&lt;/p&gt;
&lt;p&gt;I&apos;m pleased to say that as per today my course is live on &lt;a href=&quot;https://pragprog.com/&quot;&gt;The Pragmatic Bookshelf&lt;/a&gt;. I hope it will help out those who are seeking to enter this fantastic world, or those Elixir programmers who want to understand Erlang better.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;EDIT (Apr. 17, 2023): my course was retired from PragProg on Apr. 21, 2020 and moved to Udemy, but is now retired from Udemy as well.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;video-embed&quot;&gt;&lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/IwhbjqsizFk&quot; title=&quot;Embedded video&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
</content:encoded></item><item><title>Setting up multiple databases in Rails: the definitive guide</title><link>https://www.ostinelli.net/setting-multiple-databases-rails-definitive-guide/</link><guid isPermaLink="true">https://www.ostinelli.net/setting-multiple-databases-rails-definitive-guide/</guid><description>There are different reasons why you might consider having multiple databases in your Ruby on Rails application. In my specific case scenario, I needed to store large quantities of data representing user behavior: clicks, pages visited, historical changes, and so on. This kind of databases generally are not mission critical, and grow much faster (and larger)…</description><pubDate>Wed, 02 Dec 2015 18:00:34 GMT</pubDate><content:encoded>&lt;p&gt;There are different reasons why you might consider having multiple databases in your Ruby on Rails application. In my specific case scenario, I needed to store large quantities of data representing user behavior: clicks, pages visited, historical changes, and so on.&lt;/p&gt;
&lt;p&gt;This kind of databases generally are not mission critical, and grow much faster (and larger) than most databases. Their requirements are often different: for instance, they need more storage space, are more tolerant in the face of hardware or software failures, and are write-intensive. For these reasons, sometimes it is interesting to separate them from your application&apos;s primary database. Often, non-RDBMS databases are chosen for these kind of tasks, something which is however beyond the scope of this article.&lt;/p&gt;
&lt;p&gt;I googled and read many different solutions, however I couldn&apos;t find one that was able to fully cover how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have different and isolated migrations and schemas for every database.&lt;/li&gt;
&lt;li&gt;Use rails generators to create new migrations for every database, independently.&lt;/li&gt;
&lt;li&gt;Offer database-specific rake tasks for the most common database operations (i.e. like the ones available for the primary database).&lt;/li&gt;
&lt;li&gt;Integrate with RSpec&apos;s default &lt;code&gt;spec&lt;/code&gt; task.&lt;/li&gt;
&lt;li&gt;Work with &lt;a href=&quot;https://github.com/DatabaseCleaner/database_cleaner&quot;&gt;Database Cleaner&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Work on &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is my take on how to solve all of these - and have a fully working multiple database solution for your Rails application.&lt;/p&gt;

&lt;h2 id=&quot;createthe-customdatabase-files&quot;&gt;Create the custom database files&lt;/h2&gt;
&lt;p&gt;For the purpose of this tutorial, we&apos;re going to set up a second database called &lt;em&gt;Stats&lt;/em&gt;. To do so, we&apos;re going to duplicate how Rails handles the primary database, and stick to conventions.&lt;/p&gt;
&lt;p&gt;First of all, create the file &lt;code&gt;config/database_stats.yml&lt;/code&gt; and populate it as you do with the primary database&apos;s config file. Your file will look something like this:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;config/database_stats.yml&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;development&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  adapter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;postgresql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  encoding&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;utf8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  host&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;localhost&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  pool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  database&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;myapp_stats_development&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  username&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  password&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  adapter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;postgresql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  encoding&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;utf8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  host&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;localhost&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  pool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  database&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;myapp_stats_test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  username&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  password&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;production&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  adapter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;postgresql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  encoding&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;utf8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  url&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:  &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;lt;%= ENV[&quot;DATABASE_STATS_URL&quot;] %&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  pool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;lt;%= ENV[&quot;DB_POOL&quot;] || 5 %&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that I&apos;ve given specific names to the databases, trying to follow as closely as possible Rails&apos; naming conventions. Also, I&apos;ve set the database production url to an environment variable &lt;code&gt;DATABASE_STATS_URL&lt;/code&gt;. This will allow us to easily set this variable to a secondary database when deploying to Heroku.&lt;/p&gt;
&lt;p&gt;We&apos;re now going to create a directory that will hold the schema and all the migrations of the Stats database, so that it will have its own files clearly isolated from the primary database. We are basically going to duplicate Rails&apos; primary database &lt;code&gt;db&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Create the directory &lt;code&gt;db_stats&lt;/code&gt; in the Rails root and ensure to copy the structure and files of the primary database &lt;code&gt;db&lt;/code&gt; directory within it. You will have something like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-- db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   |-- migrate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   schema.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   seeds.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-- db_stats&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   |-- migrate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   schema.rb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   seeds.rb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The created files &lt;code&gt;schema.rb&lt;/code&gt; and &lt;code&gt;seeds.rb&lt;/code&gt;, together with the &lt;code&gt;migrate&lt;/code&gt; directory, should just be empty.&lt;/p&gt;
&lt;h2 id=&quot;add-rake-tasks&quot;&gt;Add Rake tasks&lt;/h2&gt;
&lt;p&gt;To handle the Stats database, and allow for its creation, migrations, schema dumping and other functionalities we&apos;re going to need custom Rake tasks. These tasks will provide us with the same functionalities that Rails provides us for the primary database.&lt;/p&gt;
&lt;p&gt;Create a new file &lt;code&gt;lib/tasks/db_stats.rake&lt;/code&gt;, and paste the following:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;lib/tasks/db_stats.rake&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;spec:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stats:db:test:prepare&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;namespace &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:stats&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  namespace &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:db&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; |ns|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:drop&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:drop&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:create&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:create&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:setup&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:setup&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:migrate&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:migrate&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:rollback&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:rollback&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:seed&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:seed&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:version&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:version&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    namespace &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:schema&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:load&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:schema:load&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:dump&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:schema:dump&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    namespace &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:test&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:prepare&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:test:prepare&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # append and prepend proper tasks to all the tasks defined here above&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ns.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tasks&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;each&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; |task|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      task.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;enhance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stats:set_custom_config&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stats:revert_to_original_config&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:set_custom_config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # save current vars&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @original_config &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      env_schema:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SCHEMA&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      config:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;dup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # set config variables for custom database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SCHEMA&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;db_stats/schema.rb&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;db&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db_stats&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;db/migrate&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db_stats/migrate&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;db/seeds&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db_stats/seeds.rb&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;config/database&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;config/database_stats.yml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:revert_to_original_config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # reset config variables to original values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SCHEMA&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; @original_config[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:env_schema&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; @original_config[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This needs a little explanation: let&apos;s break up this file in its main sections. First of all, we simply provide &quot;proxies&quot; to standard Rails database tasks, in a newly created Rake namespace &lt;code&gt;stats:db&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:drop&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:drop&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:create&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:create&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:setup&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:setup&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:migrate&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db:migrate&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we loop all of these tasks, and ensure the task &lt;code&gt;stats:set_custom_config&lt;/code&gt;  is run &lt;em&gt;before&lt;/em&gt; and the task &lt;code&gt;stats:revert_to_original_config&lt;/code&gt;  &lt;em&gt;after&lt;/em&gt; every one of the &quot;proxy&quot; tasks:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# append and prepend proper tasks to all tasks defined in stats:db namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ns.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tasks&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;each&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; |task|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  task.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;enhance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stats:set_custom_config&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    Rake&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stats:revert_to_original_config&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have to do this since, unfortunately, Rails support for multiple databases isn&apos;t that great, hence we need to provide minor hacks to make everything work. For this reason we have to set specific environment and configuration variables to custom values which match our Stats database before we run the &quot;proxy&quot; tasks, and then ensure that the original values are set back once those tasks have been run. The following two tasks do just that:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:set_custom_config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # save current vars&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  @original_config &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    env_schema:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SCHEMA&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    config:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;dup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # set config variables for custom database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SCHEMA&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;db_stats/schema.rb&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;db&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db_stats&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;db/migrate&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db_stats/migrate&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;db/seeds&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db_stats/seeds.rb&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paths&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;config/database&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;config/database_stats.yml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:revert_to_original_config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # reset config variables to original values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SCHEMA&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; @original_config[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:env_schema&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; @original_config[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how the lines 9-13 set values to the files and directories we have created in the previous steps.&lt;/p&gt;
&lt;p&gt;Finally, if you&apos;re using RSpec you can add one dependency to the &lt;code&gt;spec&lt;/code&gt; task, to ensure that the Stats database is automatically prepared when tests are run:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;task &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;spec:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stats:db:test:prepare&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once all of this is set up, we can create the Stats database and run its first migration:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;BASH&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; rake&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; stats:db:create&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; rake&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; stats:db:migrate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate the Stats database schema file in &lt;code&gt;db_stats/schema.rb&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;add-acustomgenerator&quot;&gt;Add a custom generator&lt;/h2&gt;
&lt;p&gt;Unfortunately, we cannot simply use Rails&apos; generator &lt;code&gt;ActiveRecord::Generators::MigrationGenerator&lt;/code&gt; because it &lt;a href=&quot;https://github.com/rails/rails/blob/v4.2.4/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb#L11&quot;&gt;hardcodes the parent directory of the migration&lt;/a&gt; (notice the path hardcoded to the directory &lt;code&gt;db/migrate&lt;/code&gt; in line 4 here below):&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;active_record/migration/migration_generator.rb&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; create_migration_file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  set_local_assigns!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  validate_file_name!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  migration_template @migration_template, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db/migrate/&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;#{file_name}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.rb&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Therefore, we need to have a custom generator to create migrations for the Stats database. However, we can still inherit from it and monkey patch this specific function. Create the following generator in &lt;code&gt;lib/generators/stats_migration_generator.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;lib/generators/stats_migration_generator.rb&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;rails/generators/active_record/migration/migration_generator&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StatsMigrationGenerator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ActiveRecord::Generators::MigrationGenerator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  source_root &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;File&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;File&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Generators&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;MigrationGenerator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;instance_method&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:create_migration_file&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;source_location&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;first&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;templates&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; create_migration_file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    set_local_assigns!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    validate_file_name!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    migration_template @migration_template, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;db_stats/migrate/&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;#{file_name}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.rb&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In line 9 we set the directory base to the Stats database directory. Also, in line 4 we initialize the templates directory and point it at the original one used by the generator we&apos;re inheriting from.&lt;/p&gt;
&lt;p&gt;With all of this in place, we can now generate migrations for the Stats database:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;BASH&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; rails&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; g&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; stats_migration&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; create_clicks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      create&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  db_stats/migrate/20151201191642_create_clicks.rb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&apos;ll notice that the migration file gets created in the Stats database migrate directory &lt;code&gt;db_stats/migrate&lt;/code&gt;. You can edit this file and then run your migrations with the Rake task that we&apos;ve set up in the previous steps, just as you normally would do with your primary database:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;BASH&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; rake&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; stats:db:migrate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;finalize-connection-and-models&quot;&gt;Finalize connection and models&lt;/h2&gt;
&lt;p&gt;We&apos;re almost done. Add a new initializer file &lt;code&gt;config/initializers/db_stats.rb&lt;/code&gt;  and paste the following:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;config/initializers/db_stats.rb&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# save stats database settings in global var&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_STATS&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; YAML&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ERB&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;File&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;read&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;config&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;database_stats.yml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that we reference the Stats database configuration file that we created in the first step here above. By doing this, we initialise a global variable DB_STATS that holds the current environment&apos;s configuration of the Stats database.&lt;/p&gt;
&lt;p&gt;Finally, we can set our models&apos; connection to this configuration. For example, let&apos;s say that we have a &lt;code&gt;Click&lt;/code&gt;  model that corresponds to the migration here above. All you have to do is add one extra line that specifies which connection to use:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;click.rb&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Click&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  establish_connection &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_STATS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s that easy. Your model will now use the database Stats.&lt;/p&gt;
&lt;p&gt;If you have multiple models that need to connect to the Stats database, however, you will need to add an extra step. If you were to have another model establishing its own connection to the Stats database, it would have its own connection pool and you might risk getting out of available connections to your Stats database. Therefore, if you have multiple models it is recommended to inherit from a single model, so that all the models connecting to the Stats database will share the same connection pool.&lt;/p&gt;
&lt;p&gt;To do so, create the base model that connects to the Stats database:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;click.rb&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; StatsBase&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  establish_connection &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_STATS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;abstract_class&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now inherit in all your models:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;click.rb&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Click&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;StatsBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; View&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;StatsBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;heroku&quot;&gt;Heroku&lt;/h2&gt;
&lt;p&gt;As already anticipated, the last step that you need to make this work on Heroku is to set the environment variable &lt;code&gt;DATABASE_STATS_URL&lt;/code&gt;  to the database you want to use as Stats. For example, if you created a second database called &lt;code&gt;HEROKU_POSTGRESQL_TEAL_URL&lt;/code&gt; all you have to do is to set this database&apos;s value using the &lt;a href=&quot;https://toolbelt.heroku.com/&quot;&gt;Heroku toolbelt&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ heroku config:set DATABASE_STATS_URL=postgres://gsdfjrthjsnaew:gry6OJF6drDjththjkSDngldsf@ec2-116-22-114-221.compute-1.amazonaws.com:5432/hmsrthj24dfgks&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you&apos;re ready to go.&lt;/p&gt;
&lt;h2 id=&quot;bonus-databasecleaner&quot;&gt;Bonus: DatabaseCleaner&lt;/h2&gt;
&lt;p&gt;If you&apos;re using the &lt;a href=&quot;https://github.com/DatabaseCleaner/database_cleaner&quot;&gt;DatabaseCleaner&lt;/a&gt; gem, you can set it to clean the models that use the Stats database too. For example, your &lt;code&gt;spec/rails_helper.rb&lt;/code&gt; may look something like this:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;spec/rails_helper.rb&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;RAILS_ENV&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;test&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;spec_helper&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; File&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;expand_path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;../../config/environment&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__FILE__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;rspec/rails&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Dir&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;spec/support/**/*.rb&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;each&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { |f| &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Migration&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;maintain_test_schema!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RSpec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;configure&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; |config|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;use_transactional_fixtures&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;infer_spec_type_from_file_location!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;before&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:suite&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    DatabaseCleaner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;clean_with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:truncation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    DatabaseCleaner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:active_record&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;model:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Click&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;clean_with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:truncation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;before&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:each&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; |example|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    unit_test&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:feature&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;include?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(example.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    strategy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; unit_test &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :transaction&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:truncation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    DatabaseCleaner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;strategy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; strategy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    DatabaseCleaner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:active_record&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;model:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Click&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;strategy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; strategy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    DatabaseCleaner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    DatabaseCleaner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:active_record&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;model:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Click&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;after&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:each&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    DatabaseCleaner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;clean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    DatabaseCleaner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:active_record&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;model:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Click&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }].&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;clean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;According to DatabaseCleaner &lt;a href=&quot;https://github.com/DatabaseCleaner/database_cleaner/blob/master/README.markdown&quot;&gt;README&lt;/a&gt;, it should be possible to set a &lt;em&gt;connection&lt;/em&gt; option instead of the &lt;em&gt;model&lt;/em&gt; one. Unfortunately, my attempts at this have been unsuccessful. If anyone knows how to do this and avoid specifying a DatabaseCleaner strategy for every model, please let me know.&lt;/p&gt;
&lt;p&gt;I hope you&apos;ve enjoyed reading this, and that my ramblings can be helpful to someone going down this same path. As usual, any suggestions on how to improve any of this are warmly welcome.&lt;/p&gt;
&lt;p&gt;Happy multiple db&apos;ing! :)&lt;/p&gt;
</content:encoded></item><item><title>An evaluation of Erlang global process registries: meet Syn</title><link>https://www.ostinelli.net/an-evaluation-of-erlang-global-process-registries-meet-syn/</link><guid isPermaLink="true">https://www.ostinelli.net/an-evaluation-of-erlang-global-process-registries-meet-syn/</guid><description>Due to my personal interests and history, I often find myself building applications in field of the Internet Of Things. Most of the times I end up using Erlang: it is based on the Actor&apos;s Model and is an ideological (and practical) perfect match to manage IoT interactions. I recently built an application where devices can connect to, and interact with each…</description><pubDate>Mon, 06 Jul 2015 09:44:43 GMT</pubDate><content:encoded>&lt;p&gt;Due to my personal interests and history, I often find myself building applications in field of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Internet_of_Things&quot;&gt;Internet Of Things&lt;/a&gt;. Most of the times I end up using &lt;a href=&quot;http://www.erlang.org/&quot;&gt;Erlang&lt;/a&gt;: it is based on the &lt;a href=&quot;https://en.wikipedia.org/wiki/Actor_model&quot;&gt;Actor&apos;s Model&lt;/a&gt; and is an ideological (and practical) perfect match to manage IoT interactions.&lt;/p&gt;
&lt;p&gt;I recently built an application where devices can connect to, and interact with each other. Every device is identified via a unique ID (its serial number) and based on this ID the devices can send and receive messages. Nothing new here: it&apos;s a standard messaging platform, which supports a custom protocol.&lt;/p&gt;
&lt;p&gt;Due to the large amount of devices that I needed to support, this application runs on a cluster of Erlang nodes. Once a device connects to one of those nodes, the related TCP socket events are handled by a process running on that node. To send a message to a specific device, you send a message to the process that handles the devices&apos;s TCP socket.&lt;/p&gt;
&lt;p&gt;While building this application, I was early in the process faced with a very common problem: I needed a g&lt;em&gt;lobal process registry&lt;/em&gt; that would allow me to globally register a process based on its serial number, so that messages can be sent from anywhere in the cluster. This registry would need to have the following main characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Distributed.&lt;/li&gt;
&lt;li&gt;Fast write speeds (&amp;gt;10,000 / sec).&lt;/li&gt;
&lt;li&gt;Handle naming conflict resolution.&lt;/li&gt;
&lt;li&gt;Allow for adding/removal of nodes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Therefore I started to search for possible solutions (which included posting to the &lt;a href=&quot;http://erlang.org/pipermail/erlang-questions/2015-February/083175.html&quot;&gt;Erlang Questions mailing list&lt;/a&gt;), and these came out as my options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Erlang&apos;s &lt;code&gt;global&lt;/code&gt;  module.&lt;/li&gt;
&lt;li&gt;Erlang&apos;s &lt;code&gt;pg2&lt;/code&gt;  module.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uwiger/gproc&quot;&gt;Gproc&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/okeuday/cpg&quot;&gt;CloudI Process Groups&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Roll out a custom solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-stress-test&quot;&gt;The Stress Test&lt;/h2&gt;
&lt;p&gt;I decided to evaluate every one of these solutions based on a variety of considerations. However, I also wanted to see how they would perform when submitted to some kind of a stress test. Therefore, I defined and wrote a simple one that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Launches&lt;/em&gt; a certain number of processes per node (for example, 25,000 processes per node).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Registers&lt;/em&gt; these processes (25,000 processes per node), each with a globally unique Key.&lt;/li&gt;
&lt;li&gt;Waits for those Keys to be &lt;em&gt;propagated&lt;/em&gt; to all the nodes.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Unregisters&lt;/em&gt; all of these processes.&lt;/li&gt;
&lt;li&gt;Waits for those Keys to be &lt;em&gt;removed&lt;/em&gt; from all the nodes.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Re-registers&lt;/em&gt; all of the processes, to check for unwanted effects of subsequent add/remove operations.&lt;/li&gt;
&lt;li&gt;Again, waits for those Keys to be &lt;em&gt;propagated&lt;/em&gt; to all the nodes.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Kills&lt;/em&gt; all the processes (this time, without previously unregistering them).&lt;/li&gt;
&lt;li&gt;Waits for those Keys to be removed from all the nodes (to check for &lt;em&gt;process monitoring&lt;/em&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The test measures how long each one of these steps takes.&lt;/p&gt;
&lt;p&gt;The following is the code for this stress test. You can see that it defines a behaviour: this is to implement callback modules that match the different syntax used by the different libraries.&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_registry_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register_on_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister_on_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; term&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; term&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; term&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() | &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MAX_RETRIEVE_WAITING_TIME&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;60000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, ProcessesCount, Nodes) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% connect&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	connect_nodes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Nodes),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% callback init&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	CallbackModule:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% launch processes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{UpperKey, PidInfos} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; launch_processes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, ProcessesCount),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% benchmark: register&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{TimeReg, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; timer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MODULE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [CallbackModule, PidInfos]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Registered processes in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; sec, at a rate of &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/sec&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		TimeReg&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		ProcessesCount&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;TimeReg&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% benchmark: registration propagation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{RetrievedInMs1, RetrieveProcess1} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, CallbackModule, UpperKey),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Check that process with Key &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; was found: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		UpperKey, RetrieveProcess1, RetrievedInMs1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% benchmark: unregister&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{TimeUnreg, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; timer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MODULE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [CallbackModule, PidInfos]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Unregistered processes in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; sec, at a rate of &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/sec&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		TimeUnreg&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		ProcessesCount&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;TimeUnreg&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% benchmark: unregistration propagation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{RetrievedInMs2, RetrieveProcess2} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, CallbackModule, UpperKey),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Check that process with Key &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; was NOT found: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		UpperKey, RetrieveProcess2, RetrievedInMs2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% benchmark: re-registering&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{TimeReg2, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; timer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MODULE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [CallbackModule, PidInfos]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Re-registered processes in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; sec, at a rate of &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/sec&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		TimeReg2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		ProcessesCount&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;TimeReg2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% benchmark: re-registration propagation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{RetrievedInMs3, RetrieveProcess3} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, CallbackModule, UpperKey),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Check that process with Key &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; was found: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		UpperKey, RetrieveProcess3, RetrievedInMs3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% benchmark: monitoring&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Kill all processes&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	kill_processes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PidInfos),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{RetrievedInMs4, RetrieveProcess4} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, CallbackModule, UpperKey),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Check that process with Key &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; was NOT found: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		UpperKey, RetrieveProcess4, RetrievedInMs4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connect_nodes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Nodes) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; net_kernel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connect_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node) || Node &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Nodes].&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;launch_processes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, ProcessesCount) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% return the processes info in format [{Node, [{Key, Pid}]}, ...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	Nodes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() | &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nodes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	ProcessesPerNode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; round&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ProcessesCount &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Nodes)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	UpperKey &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; integer_to_list&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ProcessesPerNode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Nodes)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	F &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, Acc) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		StartingKey &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Acc) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ProcessesPerNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		Pids &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; launch_processes_on_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, ProcessesPerNode, StartingKey, Node),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		[{Node, Pids} | Acc]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	{UpperKey, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foldl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(F, [], Nodes)}.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;launch_processes_on_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, ProcessesPerNode, StartingKey, Node) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% return the key and process in a list of format [{Key, Pid}, ...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	Seq &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		integer_to_list&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		|| Key &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;seq&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(StartingKey &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ProcessesPerNode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; StartingKey)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	[{Key, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;spawn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, CallbackModule, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [])} || Key &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Seq].&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, PidInfos) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% register in parallel on all nodes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	F &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({Node, NodePidInfos}, Acc) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		RpcKey &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;async_call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MODULE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;register_on_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			CallbackModule, NodePidInfos&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		[{Node, RpcKey} | Acc]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	RpcKeys &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foldl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(F, [], PidInfos),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% wait for registration to complete on all nodes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	FResult &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({Node, RpcKey}) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		Registered &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(RpcKey),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Registered &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; processes on node &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [Registered, Node])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(FResult, RpcKeys).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register_on_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, NodePidInfos) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	F &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({Key, Pid}) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		CallbackModule:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(F, NodePidInfos),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	length&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(NodePidInfos).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Expected, CallbackModule, Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	StartTime &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; epoch_time_ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Expected, CallbackModule, Key, StartTime).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, CallbackModule, Key, StartTime) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% wait for a pid to be returned&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CallbackModule:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;			timer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;			case&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; epoch_time_ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; StartTime &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MAX_RETRIEVE_WAITING_TIME&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;				true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;timeout_during_retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;				false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, CallbackModule, Key, StartTime)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;			end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Error} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Error};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		Pid -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			RetrievedInMs &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; epoch_time_ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; StartTime,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			{RetrievedInMs, Pid}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, CallbackModule, Key, StartTime) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% wait for undefined to be returned&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CallbackModule:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			RetrievedInMs &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; epoch_time_ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; StartTime,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			{RetrievedInMs, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Error} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Error};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		_Pid -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;			timer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;			case&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; epoch_time_ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; StartTime &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MAX_RETRIEVE_WAITING_TIME&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;				true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;timeout_during_retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;				false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, CallbackModule, Key, StartTime)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;			end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, PidInfos) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% unregister in parallel on all nodes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	F &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({Node, NodePidInfos}, Acc) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		RpcKey &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;async_call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;MODULE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;unregister_on_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		CallbackModule, NodePidInfos&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		[{Node, RpcKey} | Acc]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	RpcKeys &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foldl&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(F, [], PidInfos),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% wait for unregistration to complete on all nodes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	FResult &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({Node, RpcKey}) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		Unregistered &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(RpcKey),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Unregistered &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; processes on node &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [Unregistered, Node])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(FResult, RpcKeys).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister_on_node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, NodePidInfos) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	F &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({Key, Pid}) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		CallbackModule:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(F, NodePidInfos),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	length&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(NodePidInfos).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;kill_processes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PidInfos) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	F &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({_Node, NodePidInfos}) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Pid, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kill&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) || {_Key, Pid} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; NodePidInfos]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(F, PidInfos).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;epoch_time_ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {Mega, Sec, Micro} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; os&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;timestamp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (Mega &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1000000&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Sec) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; round&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Micro &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run this stress test:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_registry_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CallbackModule, ProcessCount, Nodes).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For instance, to launch it with the callback module &lt;code&gt;global_bench&lt;/code&gt; for 100,000 processes running on a cluster of 4 nodes &lt;code&gt;[&apos;1@127.0.0.1&apos;, &apos;2@127.0.0.1&apos;, &apos;3@127.0.0.1&apos;, &apos;4@127.0.0.1&apos;]&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_registry_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;global_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &apos;1@127.0.0.1&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &apos;2@127.0.0.1&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &apos;3@127.0.0.1&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &apos;4@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this test returns an output similar to:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered 25000 processes on node &apos;1@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered 25000 processes on node &apos;2@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered 25000 processes on node &apos;3@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered 25000 processes on node &apos;4@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered processes in 6.385835 sec, at a rate of 15659.659230155492/sec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Check that process with Key &quot;100000&quot; was found: &amp;lt;6218.25065.0&amp;gt; in 0 ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Unregistered 25000 processes on node &apos;1@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Unregistered 25000 processes on node &apos;2@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Unregistered 25000 processes on node &apos;3@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Unregistered 25000 processes on node &apos;4@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Unregistered processes in 4.481706 sec, at a rate of 22312.93172733776/sec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Check that process with Key &quot;100000&quot; was NOT found: undefined in 0 ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered 25000 processes on node &apos;1@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered 25000 processes on node &apos;2@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered 25000 processes on node &apos;3@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Registered 25000 processes on node &apos;4@127.0.0.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Re-registered processes in 4.943493 sec, at a rate of 20228.611631492146/sec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Check that process with Key &quot;100000&quot; was found: &amp;lt;6218.25065.0&amp;gt; in 0 ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Kill all processes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Check that process with Key &quot;100000&quot; was NOT found: undefined in 0 ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ok&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-process-registry-libraries&quot;&gt;The Process Registry Libraries&lt;/h2&gt;
&lt;p&gt;The following are the considerations that I made for every solution.&lt;/p&gt;
&lt;h3 id=&quot;1-erlangs-native-global-module&quot;&gt;1. Erlang&apos;s native global module&lt;/h3&gt;
&lt;h4 id=&quot;considerations&quot;&gt;Considerations&lt;/h4&gt;
&lt;p&gt;The Erlang global module has native functionalities to support a global process registry. I was not particularly attracted to it, because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I always think that this module should be used to identify application&apos;s long-running services.&lt;/li&gt;
&lt;li&gt;I didn&apos;t know if millions of entries can be supported. This module wasn&apos;t built with my use case in mind: as per my previous point, it is generally used to register long-running processes.&lt;/li&gt;
&lt;li&gt;It has a locking mechanism to ensure that the registration is atomic. I felt this could become a serious bottleneck to the registration of processes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, this is a native Erlang module, which also allows to define a resolve function to be used for conflict resolution (i.e. in case of race conditions, or during net splits, when a Key gets registered simultaneously on two different nodes). It is able to satisfy the distributed requirements out of the box, with no need for additional libraries.&lt;/p&gt;
&lt;h4 id=&quot;stress-test&quot;&gt;Stress Test&lt;/h4&gt;
&lt;p&gt;I gave it a go at my stress test, with the following callback module:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;global_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;behaviour&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_registry_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	yes&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; global&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register_name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, _Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	global&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister_name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	global&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;whereis_name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;process_loop&lt;/code&gt; (which is the loop running in the processes) does nothing, except keeping the process alive.&lt;/p&gt;
&lt;p&gt;The results of the stress test are:&lt;/p&gt;
&lt;p&gt;[table colalign=&quot;left|right|right|right|right&quot;]&lt;br&gt;
,1 Node,2 Nodes,3 Nodes,4 Nodes&lt;br&gt;
Reg / second,&quot;27,233&quot;,&quot;2,673&quot;,&quot;1,997&quot;,&quot;1,579&quot;&lt;br&gt;
Retrieve registered Key (ms),0,0,0,0&lt;br&gt;
Unreg / second,&quot;29,491&quot;,&quot;2,908&quot;,&quot;2,206&quot;,&quot;1,596&quot;&lt;br&gt;
Retrieve unregistered Key (ms),0,0,0,0&lt;br&gt;
Re-Reg / second,&quot;27,149&quot;,&quot;2,993&quot;,&quot;2,131&quot;,&quot;2,542&quot;&lt;br&gt;
Retrieve re-registered Key (ms),0,0,0,0&lt;br&gt;
Retrieve Key of killed Pid (ms),0,&lt;strong&gt;timeout&lt;/strong&gt;,&lt;strong&gt;timeout&lt;/strong&gt;,&lt;strong&gt;timeout&lt;/strong&gt;&lt;br&gt;
[/table]&lt;/p&gt;
&lt;h4 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The locking mechanism heavily influences the decrease in performance that can be seen when adding nodes. With a cluster of 2+ nodes we already are under the spec of 10,000 registrations / second.&lt;/li&gt;
&lt;li&gt;The monitoring of processes is slow. After having killed all the processes, in a cluster of 2+ nodes it takes more than 60 seconds to have &lt;code&gt;global:whereis_name/1&lt;/code&gt; return &lt;code&gt;undefined&lt;/code&gt; (this is what &lt;em&gt;timeout&lt;/em&gt; means in the table here above). I had to decrease the number of processes to around 80,000 to have the stress test pass in a cluster of 4 nodes, and it would take around 55 seconds for a killed process&apos; Key to be removed from the registry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For these reasons, it didn&apos;t look like I could use this module.&lt;/p&gt;
&lt;h3 id=&quot;2-erlangs-native-pg2module&quot;&gt;2. Erlang&apos;s native pg2 module&lt;/h3&gt;
&lt;h4 id=&quot;considerations-1&quot;&gt;Considerations&lt;/h4&gt;
&lt;p&gt;Erlang pg2 module has native functionalities to support a global process registry. I was not particularly attracted to it, because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This library handles Process Groups, which is very different from handling unique Registered Names. We can use it for our purpose though, by basically creating Groups with a single entry. These groups are named according to our Keys, and every Group has a single entry: the Pid that we are registering. This is kind of a trick, but it&apos;s not a showstopper.&lt;/li&gt;
&lt;li&gt;Having Process Groups basically means that conflict resolution isn&apos;t covered. If two processes are registered on different nodes with the same Key (because of race conditions or during a net split) this will result in having a Process Group with two elements instead of one. Sometimes this is fine; however, I wanted to ensure that there would be a clearly identified single Pid per device in the whole system. Not a showstopper either, but a turn-off.&lt;/li&gt;
&lt;li&gt;I didn&apos;t know if millions of entries can be supported. This module wasn&apos;t built with my use case in mind.&lt;/li&gt;
&lt;li&gt;Here too, it has a locking mechanism to ensure that the registration is atomic which could become a bottleneck to the registration of processes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;stress-test-1&quot;&gt;Stress Test&lt;/h4&gt;
&lt;p&gt;Here&apos;s the callback module:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pg2_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;behaviour&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_registry_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pg2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key), &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;%% create group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pg2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid). &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;%% add pid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, _Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pg2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pg2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get_members&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;no_such_group&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key}} -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		[] -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		[Pid] -&amp;gt; Pid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The results of the stress test are:&lt;/p&gt;
&lt;p&gt;[table colalign=&quot;left|right|right|right|right&quot;]&lt;br&gt;
,1 Node,2 Nodes,3 Nodes,4 Nodes&lt;br&gt;
Reg / second,&quot;25,062&quot;,&quot;3,823&quot;,&quot;2,914&quot;,&quot;1,862&quot;&lt;br&gt;
Retrieve registered Key (ms),0,0,0,0&lt;br&gt;
Unreg / second,&quot;39,522&quot;,&quot;6,903&quot;,&quot;5,191&quot;,&quot;3,425&quot;&lt;br&gt;
Retrieve unregistered Key (ms),0,0,0,0,&lt;br&gt;
Re-Reg / second,&quot;25,701&quot;,&quot;3,794&quot;,&quot;2,783&quot;,&quot;1,817&quot;&lt;br&gt;
Retrieve re-registered Key (ms),0,0,0,0&lt;br&gt;
Retrieve Key of killed Pid (ms),&lt;strong&gt;timeout&lt;/strong&gt;,&lt;strong&gt;timeout,&lt;strong&gt;timeout&lt;/strong&gt;,&lt;strong&gt;timeout&lt;/strong&gt;&lt;/strong&gt;&lt;br&gt;
[/table]&lt;/p&gt;
&lt;h4 id=&quot;conclusions-1&quot;&gt;Conclusions&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The locking mechanism heavily influences the decrease in performance that can be seen when adding nodes. With a cluster of 2+ nodes we already are under the spec of 10,000 registrations / second.&lt;/li&gt;
&lt;li&gt;The monitoring of processes is slow. After having killed all the processes, even on a single nodes it takes more than 60 seconds to have &lt;code&gt;pg2:get_members/1&lt;/code&gt; return that the group no longer exits. I had to decrease the number of processes to around 45,000 to have the stress test pass in a cluster of 4 nodes, and it would take a little less than 60 seconds for a killed process&apos; Key to be removed from the registry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For these reasons, it didn&apos;t look like I could use this module.&lt;/p&gt;
&lt;h3 id=&quot;3gproc&quot;&gt;3. Gproc&lt;/h3&gt;
&lt;h4 id=&quot;considerations-2&quot;&gt;Considerations&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/uwiger/gproc&quot;&gt;gproc&lt;/a&gt; is a well-known process registry which is normally used for the additional features that it provides on top of Erlang&apos;s native process dictionary (for instance, it is able to provide pub/sub patterns). It is a solid and well-supported library, and you can often see Ulf Wiger (one of the library&apos;s authors) generously providing support for it.&lt;/p&gt;
&lt;p&gt;However, there were some concerns I had:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For the distributed part it relies on &lt;code&gt;gen_leader&lt;/code&gt;, on which I&apos;ve heard too many horror stories (maybe that&apos;s not a thing anymore). Ulf pointed me to a gproc &lt;a href=&quot;https://github.com/uwiger/gproc/tree/uw-locks_leader&quot;&gt;branch that uses locks_leader&lt;/a&gt;, where he is mainly concentrating his efforts for gproc&apos;s support for distributed operations.&lt;/li&gt;
&lt;li&gt;I felt that the main purpose of this library is not to provide a &lt;em&gt;distributed&lt;/em&gt; process registry as much as &lt;em&gt;extending&lt;/em&gt; the existing Erlang registration mechanisms with some additional features. The README in gproc&apos;s Github page clearly depicts it as being an &quot;Extended process dictionary&quot;; it just felt that the distributed part hasn&apos;t been the primary focus in the development of this library.&lt;/li&gt;
&lt;li&gt;I could not understand how conflict resolution is managed in a distributed environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;stress-test-2&quot;&gt;Stress Test&lt;/h4&gt;
&lt;p&gt;Here&apos;s the callback module:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gproc_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;behaviour&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_registry_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% start app on every node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	Nodes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() | &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nodes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	F &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ensure_all_started&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;gproc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;gproc_dist&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [Nodes])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(F, Nodes).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	Pid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;reg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		done&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	Pid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;unreg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		done&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; gproc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lookup_pid&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;EXIT&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		Pid -&amp;gt; Pid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		{Sender, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;reg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;			gproc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key}, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ignored&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			Sender &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; done&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;			process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		{Sender, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;unreg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;			gproc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unreg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key}),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;			Sender &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; done&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;			process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: in gproc, to ensure thread safety, a process can only set its own values. That&apos;s why the &lt;code&gt;register/2&lt;/code&gt; and &lt;code&gt;unregister/2&lt;/code&gt; callbacks here above send messages to the processes, which then register or unregister themselves (see &lt;code&gt;process_loop&lt;/code&gt;). As you can see here above I&apos;ve decided to provide a locking call for these functions (by using a &lt;code&gt;receive&lt;/code&gt; block), to emulate the locking calls that I&apos;ve used in the other libraries.&lt;/p&gt;
&lt;p&gt;The results of the stress test are:&lt;/p&gt;
&lt;p&gt;[table colalign=&quot;left|right|right|right|right&quot;]&lt;br&gt;
,1 Node,2 Nodes,3 Nodes,4 Nodes&lt;br&gt;
Reg / second,&quot;67,011&quot;,&quot;19,111&quot;,&quot;22,048&quot;,&quot;15,659&quot;&lt;br&gt;
Retrieve registered Key (ms),0,0,0,0&lt;br&gt;
Unreg / second,&quot;118,228&quot;,&quot;22,845&quot;,&quot;24,282&quot;,&quot;22,312&quot;&lt;br&gt;
Retrieve unregistered Key (ms),0,0,0,0&lt;br&gt;
Re-Reg / second,&quot;127,200&quot;,&quot;22,115&quot;,&quot;25,884&quot;,&quot;20,228&quot;&lt;br&gt;
Retrieve re-registered Key (ms),0,0,0,0&lt;br&gt;
Retrieve Key of killed Pid (ms),178,&quot;1,890&quot;,&quot;7,584&quot;,&quot;10,600&quot;&lt;br&gt;
[/table]&lt;/p&gt;
&lt;h4 id=&quot;conclusions-2&quot;&gt;Conclusions&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;These are overall very good results.&lt;/li&gt;
&lt;li&gt;I didn’t need to reduce the process count to make all of the test pass.&lt;/li&gt;
&lt;li&gt;The monitoring of processes can be optimized. After having killed all the processes, on a cluster of 4 nodes it takes &amp;gt;10 seconds for &lt;code&gt;gproc:lookup_pid/1&lt;/code&gt; to not find the Pid once a process has exited.&lt;/li&gt;
&lt;li&gt;Unfortunately, I had some inconsistent results running this test in a cluster of 2+ nodes. Often, the test could not retrieve the registered Key (after the first registration round) in less than 60 second, and timed out.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was a little skeptical though on the inconsistency that I saw in the test results, which might be related to the &lt;code&gt;gen_leader&lt;/code&gt;  issues that I&apos;ve occasionally heard about. The author&apos;s choice to move towards &lt;code&gt;locks_leader&lt;/code&gt; might be a sign of this. Despite these thoughts, this looked like a good potential candidate.&lt;/p&gt;
&lt;h3 id=&quot;4-cloudi-process-groups&quot;&gt;4. CloudI Process Groups&lt;/h3&gt;
&lt;h4 id=&quot;considerations-3&quot;&gt;Considerations&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/okeuday/cpg&quot;&gt;cpg&lt;/a&gt; is an actively maintained library, and his main author Michael Truog is often very available to discuss his choices and provide support. cpg deals with Process Groups and not unique Registered Names, therefore my concerns where similar to the ones I had with pg2:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Handling Process Groups is very different from handling unique Registered Names. We can use the same trick used with pg2, i.e. creating Process Groups named with Key, with a single entry (the Pid).&lt;/li&gt;
&lt;li&gt;Here too, having Process Groups basically means that conflict resolution isn&apos;t covered. This made me a little uncomfortable because I wanted to ensure that there would be a clearly identified single Pid per device in the whole system.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;stress-test-3&quot;&gt;Stress Test&lt;/h4&gt;
&lt;p&gt;Here&apos;s the callback module:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cpg_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;behaviour&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_registry_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% start app on every node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	Nodes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() | &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nodes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	[&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;reltool_util&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;application_start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cpg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]) ||  Node &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Nodes].&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cpg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(_Key, Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cpg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;leave&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Pid).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cpg&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get_members&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key, [Pid]} -&amp;gt; Pid;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;no_such_group&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Key}} -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;		Error -&amp;gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Error}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The results of the stress test are:&lt;/p&gt;
&lt;p&gt;[table colalign=&quot;left|right|right|right|right&quot;]&lt;br&gt;
,1 Node,2 Nodes,3 Nodes,4 Nodes&lt;br&gt;
Reg / second,&quot;110,198&quot;,&quot;42,680&quot;,&quot;20,703&quot;,&quot;8,488&quot;&lt;br&gt;
Retrieve registered Key (ms),0,0,0,0&lt;br&gt;
Unreg / second,&quot;109,374&quot;,&quot;32,264&quot;,&quot;25,599&quot;,&quot;15,128&quot;&lt;br&gt;
Retrieve unregistered Key (ms),0,1,0,0&lt;br&gt;
Re-Reg / second,&quot;126,791&quot;,&quot;30,862&quot;,&quot;32,138&quot;,&quot;20,791&quot;&lt;br&gt;
Retrieve re-registered Key (ms),0,0,0,0&lt;br&gt;
Retrieve Key of killed Pid (ms),&lt;strong&gt;error&lt;/strong&gt;,&lt;strong&gt;error&lt;/strong&gt;,&lt;strong&gt;error&lt;/strong&gt;,&lt;strong&gt;error&lt;/strong&gt;&lt;br&gt;
[/table]&lt;/p&gt;
&lt;h4 id=&quot;conclusions-3&quot;&gt;Conclusions&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;These are overall very good results.&lt;/li&gt;
&lt;li&gt;I was surprised of the major drop in a cluster of 4 nodes. I run this test multiple times and it always returned similar results.&lt;/li&gt;
&lt;li&gt;The monitoring of processes didn&apos;t work appropriately. Even on a single node, the test experienced an internal timeout:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&apos;EXIT&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; {timeout,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  {gen_server,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   call,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   [cpg_default_scope,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {get_members,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &quot;100000&quot;}]}}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had to decrease the number of processes to around 25,000 to have the stress test pass in a cluster of 4 nodes. The monitoring issue didn&apos;t make me feel particularly at ease, however this library did look like a potential candidate.&lt;/p&gt;
&lt;h3 id=&quot;5custom-solution-syn&quot;&gt;5. Custom Solution: Syn&lt;/h3&gt;
&lt;h4 id=&quot;considerations-4&quot;&gt;Considerations&lt;/h4&gt;
&lt;p&gt;Since it became clear that I could not use Erlang&apos;s native &lt;code&gt;global&lt;/code&gt; or &lt;code&gt;pg2&lt;/code&gt; modules, and that the two other libraries I looked into were candidates but each one with their own little twerks, I decided to try a custom solution, which I called &lt;code&gt;syn&lt;/code&gt;  (short for &lt;em&gt;synonym&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;In any distributed system you are faced with a consistency challenge, which is often resolved by having one master arbiter performing all write operations (chosen with a mechanism of leader election), or through atomic transactions. As said here above, I needed a global process registry for an application of the IoT field. In this context, Keys used to identify a process are often the physical object&apos;s unique identifier (for instance, its serial or mac address), and are therefore already defined and unique before hitting the system. The consistency challenge is less of a problem in this case, since the likelihood of concurrent incoming requests that would register processes with the same Key is extremely low and, in most cases, acceptable.&lt;/p&gt;
&lt;p&gt;Therefore, Availability has been chosen over Consistency and Syn is &lt;a href=&quot;http://en.wikipedia.org/wiki/Eventual_consistency&quot;&gt;eventually consistent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Under the hood, Syn performs dirty reads and writes into a distributed in-memory Mnesia table, replicated across all the nodes of the cluster. This made me feel comfortable that I wouldn&apos;t need to reinvent the replication mechanisms of Erlang&apos;s native DB, however I needed a way to handle conflict resolution and net splits. For this reason, Syn can automatically manage conflict resolution by implementing a specialized and simplified version of the mechanisms used in Ulf Wiger&apos;s &lt;a href=&quot;https://github.com/uwiger/unsplit&quot;&gt;unsplit&lt;/a&gt; framework.&lt;/p&gt;
&lt;p&gt;You can read more about Syn in its &lt;a href=&quot;https://github.com/ostinelli/syn&quot;&gt;github repo&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;stress-test-4&quot;&gt;Stress Test&lt;/h4&gt;
&lt;p&gt;Here&apos;s the callback module:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;syn_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;behaviour&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_registry_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;	%% start app on every node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	Nodes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() | &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nodes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	F &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;syn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;		rpc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Node, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;syn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(F, Nodes).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; syn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, Pid).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key, _Pid) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;	ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; syn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unregister&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;retrieve&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;	syn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;find_by_key&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Key).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;		_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;	end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The results of the stress test are:&lt;br&gt;
[table colalign=&quot;left|right|right|right|right&quot;]&lt;br&gt;
,1 Node,2 Nodes,3 Nodes,4 Nodes&lt;br&gt;
Reg / second,&quot;106,324&quot;,&quot;52,792&quot;,&quot;60,958&quot;,&quot;40,929&quot;&lt;br&gt;
Retrieve registered Key (ms),0,0,0,56&lt;br&gt;
Unreg / second,&quot;105,506&quot;,&quot;50,591&quot;,&quot;67,042&quot;,&quot;42,896&quot;&lt;br&gt;
Retrieve unregistered Key (ms),0,0,0,0&lt;br&gt;
Re-Reg / second,&quot;106,424&quot;,&quot;51,322&quot;,&quot;77,258&quot;,&quot;47,125&quot;&lt;br&gt;
Retrieve re-registered Key (ms),0,0,0,0&lt;br&gt;
Retrieve Key of killed Pid (ms),719,995,&quot;1,577&quot;,&quot;1,825&quot;&lt;br&gt;
[/table]&lt;/p&gt;
&lt;h4 id=&quot;conclusions-4&quot;&gt;Conclusions&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;These are overall very good results. I&apos;m not sure why Syn is performing better with 3 nodes than with 2 (and I&apos;ve repeated this test more than once).&lt;/li&gt;
&lt;li&gt;I didn&apos;t need to reduce the process count to make all of the test pass.&lt;/li&gt;
&lt;li&gt;The monitoring of processes worked appropriately.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;final-notes&quot;&gt;Final notes&lt;/h2&gt;
&lt;p&gt;I want to stress out how comparisons and these tests are difficult to perform. Every library behaves differently, and it is hard (if not impossible) to define some kind of a common stress test to allow for a better understanding of their performance levels. I gave it a go, but looking at the above definition of my stress test for instance I ask myself: &quot;Why did I set the process count to 100,000? I can see that most libraries behave fine with lower numbers&quot;. Also, &quot;What would happen if instead of registering processes sequentially in a single process per node, we had them register themselves simultaneously, therefore increasing the load on the registry?&quot;. More importantly, &quot;Does this test represent some kind of real life scenario?&quot;.&lt;/p&gt;
&lt;p&gt;This article wants to share my thoughts and how I ended up writing Syn. Sure, Syn performs well in the defined use case and stress test, but this does in no way mean that the other libraries here won&apos;t perform way better in other stress tests and scenarios. I&apos;d actually be glad to know that someone else is willing to take the time to evaluate these, and other, global process registries. They are a kind of holy grail; and let&apos;s remember that anything distributed is never easy, nor given.&lt;/p&gt;
&lt;p&gt;As a final note, I&apos;d enjoy reading comments from the library authors or other Erlang enthusiasts. This is such a delicate matter that I&apos;d love to have a healthy exchange of opinions, hopefully contributing to improving all of our experiences.&lt;/p&gt;
</content:encoded></item><item><title>How to build a Rails API server: Optimizing the framework</title><link>https://www.ostinelli.net/how-to-build-a-rails-api-server-optimizing-the-framework/</link><guid isPermaLink="true">https://www.ostinelli.net/how-to-build-a-rails-api-server-optimizing-the-framework/</guid><description>I have been developing Rails JSON API applications for quite some time now, and I&apos;d like to share a few of my setups and discuss why I do things this way. I&apos;m starting today a series of articles that will cover up pretty much the steps I take every time I bootstrap a new Rails JSON API application. One of the first things I do is to ensure I&apos;m optimizing…</description><pubDate>Tue, 23 Jun 2015 16:54:44 GMT</pubDate><content:encoded>&lt;p&gt;I have been developing Rails JSON API applications for quite some time now, and I&apos;d like to share a few of my setups and discuss why I do things this way. I&apos;m starting today a series of articles that will cover up pretty much the steps I take every time I bootstrap a new Rails JSON API application.&lt;/p&gt;
&lt;p&gt;One of the first things I do is to ensure I&apos;m optimizing Rails for speed. I basically optimize the framework itself, prior coding any specific application logic.&lt;/p&gt;
&lt;p&gt;You may have heard before that &quot;&lt;a href=&quot;http://c2.com/cgi/wiki?PrematureOptimization&quot;&gt;Premature optimization is the root of all evil&lt;/a&gt;&quot;. However, &quot;Premature optimization is a phrase used to describe a situation where a programmer lets performance considerations affect the design of a piece of code&quot;, which &quot;can result in a design that is not as clean as it could have been or code that is incorrect, because the code is complicated by the optimization and the programmer is distracted by optimizing&quot; (source: &lt;a href=&quot;https://en.wikipedia.org/wiki/Program_optimization&quot;&gt;WikiPedia&lt;/a&gt;). This is not what we&apos;re doing here: we&apos;re just going to apply a few changes to Rails, and then basically forget about those and start coding in a framework that is optimized to serve our API.&lt;/p&gt;
&lt;p&gt;Many of Rails functionalities are simply not needed when building an API server, and by stripping down Rails to a bare minimum we can actually achieve pretty significant performance increases.&lt;/p&gt;

&lt;h3 id=&quot;greenfield-ruby-on-rails&quot;&gt;Greenfield Ruby On Rails&lt;/h3&gt;
&lt;p&gt;Let&apos;s first see what an empty project can achieve. I&apos;m currently using Ruby 2.2.2 and Rails 4.2.1. Let&apos;s create a new Rails application:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;rails new api_greenfield -T&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s add a production server. For the scope of this post, it&apos;s not really important what we use, as long as it&apos;s a server that we can use in production. We are going to benchmark the results we get after applying our changes to Rails, so the absolute values resulting from our benchmarks are not as important as the relative improvements that we see in speed.&lt;/p&gt;
&lt;p&gt;We&apos;re going to use &lt;a href=&quot;http://puma.io/&quot;&gt;Puma&lt;/a&gt;, as it is now the &lt;a href=&quot;https://devcenter.heroku.com/changelog-items/594&quot;&gt;recommended Ruby webserver by Heroku&lt;/a&gt; (and as I host most of my applications there, using it has become my default choice). Add it to the project Gemfile:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;Gemfile&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;https://rubygems.org&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ruby &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;2.2.2&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;rails&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;4.2.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;sqlite3&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;puma&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then &lt;code&gt;bundle install&lt;/code&gt;. Create a Puma configuration file &lt;code&gt;config/puma.rb&lt;/code&gt;  and set the following basic params:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;workers &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;threads_count&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;threads threads_count, threads_count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;preload_app!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;rackup &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DefaultRackup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;port &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;PORT&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;environment &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;RAILS_ENV&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;development&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;on_worker_boot &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # Worker specific setup for Rails 4.1+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  ActiveRecord&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Base&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;establish_connection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now need to set up a simple response page that we will hit with our benchmarks. We&apos;re going to create a controller and an action that responds with a JSON body to the entry point &lt;code&gt;/benchmarks/simple&lt;/code&gt;. To do so, let&apos;s create &lt;code&gt;benchmarks_controller.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BenchmarksController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; simple&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # example from http://json.org/example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    json&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      glossary:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        title:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;example glossary&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        gloss_div:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          title:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;S&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;          gloss_list:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            gloss_entry:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              id:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;SGML&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              sort_as:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;SGML&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              gloss_term:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Standard Generalized Markup Language&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              acronym:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;SGML&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              abbrev:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;ISO 8879:1986&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              gloss_def:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                para:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;A meta-markup language, used to create markup languages such as DocBook.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                gloss_see_also:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;GML&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;XML&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;              gloss_see:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;markup&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    render &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;json:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set the routes for this controller:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Rails&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;routes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;draw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  resources &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:benchmarks&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;only:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :none&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    collection &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      get &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:simple&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start Puma in production:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;BASH&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;RAILS_ENV&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;production&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; bundle&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; exec&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; puma&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -C&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; config/puma.rb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify that Rails responds with our JSON body at the chosen entry point:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl -H &quot;Content-type: application/json&quot; http://127.0.0.1:3000/benchmarks/simple&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&quot;glossary&quot;:{&quot;title&quot;:&quot;example glossary&quot;,&quot;gloss_div&quot;:{&quot;title&quot;:&quot;S&quot;,&quot;gloss_list&quot;:{&quot;gloss_entry&quot;:{&quot;id&quot;:&quot;SGML&quot;,&quot;sort_as&quot;:&quot;SGML&quot;,&quot;gloss_term&quot;:&quot;Standard Generalized Markup Language&quot;,&quot;acronym&quot;:&quot;SGML&quot;,&quot;abbrev&quot;:&quot;ISO 8879:1986&quot;,&quot;gloss_def&quot;:{&quot;para&quot;:&quot;A meta-markup language, used to create markup languages such as DocBook.&quot;,&quot;gloss_see_also&quot;:[&quot;GML&quot;,&quot;XML&quot;]},&quot;gloss_see&quot;:&quot;markup&quot;}}}}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The server is up and ready. We can now benchmark our greenfield Rails application running with Puma. We will use the basic &lt;a href=&quot;http://httpd.apache.org/docs/2.2/programs/ab.html&quot;&gt;Apache Benchmark&lt;/a&gt; tool to do so.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ ab -c 5 -n 10000 -H &quot;Content-type: application/json&quot; http://127.0.0.1:3000/benchmarks/simple&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;This is ApacheBench, Version 2.3 &amp;lt;$Revision: 1604373&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gt; Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Server Hostname: 127.0.0.1 Server Port: 3000 Document Path: /benchmarks/simple Document Length: 369 bytes Concurrency Level: 5 Time taken for tests: 4.676 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 6990000 bytes HTML transferred: 3690000 bytes Requests per second: 2138.53 [#/sec] (mean) Time per request: 2.338 [ms] (mean) Time per request: 0.468 [ms] (mean, across all concurrent requests) Transfer rate: 1459.79 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.0 0 0 Processing: 1 2 1.0 2 27 Waiting: 1 2 1.0 2 27 Total: 1 2 1.0 2 27 Percentage of the requests served within a certain time (ms) 50% 2 66% 2 75% 3 80% 3 90% 3 95% 4 98% 4 99% 5 100% 27 (longest request)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is actually not bad at all! A greenfield Rails project is able to sustain &lt;em&gt;2,138&lt;/em&gt; req/sec. Obviously, this is without any application logic, nor database calls, but it is still a good starting point.&lt;/p&gt;
&lt;h3 id=&quot;the-rails-apigem&quot;&gt;The Rails API gem&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/rails-api/rails-api&quot;&gt;Rails API gem&lt;/a&gt; is &quot;a subset of a normal Rails application, created for applications that don&apos;t require all functionality that a complete Rails application provides. It is a bit more lightweight, and consequently a bit faster than a normal Rails application. The main example for its usage is in API applications only, where you usually don&apos;t need the entire Rails middleware stack nor template generation&quot;.  Note that &lt;a href=&quot;http://wyeworks.com/blog/2015/4/20/rails-api-is-going-to-be-included-in-rails-5/&quot;&gt;Rails API will be part of Rails 5&lt;/a&gt;, but for now we still have to include the gem:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;https://rubygems.org&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ruby &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;2.2.2&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;rails&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;4.2.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;rails-api&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;sqlite3&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;puma&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&apos;t forget to &lt;code&gt;bundle install&lt;/code&gt;. Then, change our &lt;code&gt;benchmarks_controller.rb&lt;/code&gt; to inherit from the Rails::API Action Controller:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BenchmarksController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ActionController::API&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, comment out in &lt;code&gt;application_controller.rb&lt;/code&gt; :&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# protect_from_forgery with: :exception&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s try a new benchmark (portions omitted):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ ab -c 5 -n 10000 -H &quot;Content-type: application/json&quot; http://127.0.0.1:3000/benchmarks/simple&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Concurrency Level:      5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time taken for tests:   4.220 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Complete requests:      10000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Failed requests:        0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Total transferred:      6990000 bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTML transferred:       3690000 bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Requests per second:    2369.39 [#/sec] (mean)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time per request:       2.110 [ms] (mean)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time per request:       0.422 [ms] (mean, across all concurrent requests)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Transfer rate:          1617.39 [Kbytes/sec] received&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connection Times (ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              min  mean[+/-sd] median   max&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connect:        0    0   0.0      0       0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Processing:     1    2   0.9      2      27&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Waiting:        1    2   0.9      2      27&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Total:          1    2   0.9      2      27&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Percentage of the requests served within a certain time (ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  50%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  66%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  75%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  80%      3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  90%      3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  95%      3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  98%      4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  99%      4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; 100%     27 (longest request)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now see a response rate of &lt;em&gt;2,369&lt;/em&gt; req/sec, which is an increase in performance of ~11% over greenfield Rails. This is a modest improvement, but an improvement nonetheless.&lt;/p&gt;
&lt;h3 id=&quot;oj&quot;&gt;OJ&lt;/h3&gt;
&lt;p&gt;Rails&apos; default JSON serializer isn&apos;t the fastest out there, so let&apos;s swap it for &lt;a href=&quot;https://github.com/ohler55/oj&quot;&gt;Oj&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;https://rubygems.org&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ruby &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;2.2.2&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;rails&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;4.2.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;rails-api&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;sqlite3&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;puma&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;oj&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;oj_mimic_json&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s run the benchmark with Oj (portions omitted):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ ab -c 5 -n 10000 -H &quot;Content-type: application/json&quot; http://127.0.0.1:3000/benchmarks/simple&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Concurrency Level:      5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time taken for tests:   4.040 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Complete requests:      10000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Failed requests:        0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Total transferred:      6990000 bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTML transferred:       3690000 bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Requests per second:    2475.34 [#/sec] (mean)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time per request:       2.020 [ms] (mean)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time per request:       0.404 [ms] (mean, across all concurrent requests)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Transfer rate:          1689.71 [Kbytes/sec] received&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connection Times (ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              min  mean[+/-sd] median   max&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connect:        0    0   0.3      0      27&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Processing:     1    2   0.8      2      29&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Waiting:        1    2   0.8      1      29&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Total:          1    2   0.9      2      29&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;WARNING: The median and mean for the waiting time are not within a normal deviation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        These results are probably not that reliable.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Percentage of the requests served within a certain time (ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  50%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  66%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  75%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  80%      3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  90%      3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  95%      3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  98%      3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  99%      4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; 100%     29 (longest request)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see a small improvement here, which is practically irrelevant (~4%) as we hit &lt;em&gt;2,475&lt;/em&gt; req/sec. The switch to Oj is going to be more relevant the bigger the JSON objects to serialize are, but at this stage it doesn&apos;t hurt to keep Oj in here.&lt;/p&gt;
&lt;h3 id=&quot;actioncontrollermetal&quot;&gt;ActionController::Metal&lt;/h3&gt;
&lt;p&gt;It is now time to give the final boost, by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removing unnecessary railties.&lt;/li&gt;
&lt;li&gt;Using Rails&apos; &lt;em&gt;ActionController::Metal&lt;/em&gt; instead of the base controllers that our &lt;em&gt;BenchmarkController&lt;/em&gt; has inherited from until now.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, remove unnecessary imports from &lt;code&gt;application.rb&lt;/code&gt; (your mileage may vary - this is my standard setup and I&apos;ve rarely needed anything else):&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# require &quot;active_model/railtie&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# require &quot;active_job/railtie&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;active_record/railtie&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# require &quot;action_controller/railtie&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;action_mailer/railtie&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# require &quot;action_view/railtie&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# require &quot;sprockets/railtie&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Second (and this is what is really going to make a difference), we&apos;re going to create a new controller that all of our API controllers are going to inherit from. Let&apos;s create our base &lt;code&gt;api_controller.rb&lt;/code&gt; :&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ApiController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ActionController::Metal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  abstract!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  include&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; AbstractController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Callbacks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  include&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ActionController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RackDelegation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  include&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ActionController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;StrongParameters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  private&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; render&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(options&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; options[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:status&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 200&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;content_type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;application/json&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    body&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Oj&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;dump&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(options[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:json&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;mode:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :compat&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Content-Length&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;bytesize&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;to_s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;response_body&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  ActiveSupport&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;run_load_hooks&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:action_controller&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, in this controller we define our custom render method. By default, I&apos;ve already included the three modules that I basically use everywhere:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;AbstractController::Callbacks&lt;/em&gt; which allows you to set callbacks such as &lt;code&gt;before_action&lt;/code&gt;  in your controllers.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;ActionController::RackDelegation&lt;/em&gt; which is needed to set the &lt;code&gt;response_body&lt;/code&gt;  (called in the &lt;code&gt;render&lt;/code&gt;  method).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;ActionController::StrongParameters&lt;/em&gt; which allows you to use Strong Params in your controllers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other modules that you might want to include here are, for instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;ActionController::HttpAuthentication::Token::ControllerMethods&lt;/em&gt; to use the &lt;code&gt;authenticate_with_http_token&lt;/code&gt;  helper method if you are going to use token authentication in your API.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;ActionController::HttpAuthentication::Basic::ControllerMethods&lt;/em&gt; to use the &lt;code&gt;authenticate_with_http_basic&lt;/code&gt;  helper method if you are going to use basic authentication in your API.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now for our benchmarks, let&apos;s ensure that &lt;code&gt;benchmarks_controller.rb&lt;/code&gt;  inherits from our newly created controller:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BenchmarksController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ApiController&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are the results of the benchmark that includes all of above changes (portions omitted):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ ab -c 5 -n 10000 -H &quot;Content-type: application/json&quot; http://127.0.0.1:3000/benchmarks/simple&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Concurrency Level:      5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time taken for tests:   2.377 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Complete requests:      10000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Failed requests:        0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Total transferred:      7200000 bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTML transferred:       3690000 bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Requests per second:    4206.19 [#/sec] (mean)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time per request:       1.189 [ms] (mean)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time per request:       0.238 [ms] (mean, across all concurrent requests)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Transfer rate:          2957.48 [Kbytes/sec] received&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connection Times (ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              min  mean[+/-sd] median   max&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connect:        0    0   0.0      0       0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Processing:     1    1   0.4      1       5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Waiting:        0    1   0.4      1       5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Total:          1    1   0.4      1       5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Percentage of the requests served within a certain time (ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  50%      1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  66%      1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  75%      1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  80%      1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  90%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  95%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  98%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  99%      2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; 100%      5 (longest request)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time the impact is notable, as we hit &lt;em&gt;4,206&lt;/em&gt; req/sec.&lt;/p&gt;
&lt;h3 id=&quot;final-touch&quot;&gt;Final Touch&lt;/h3&gt;
&lt;p&gt;With our latest &lt;em&gt;ApiController&lt;/em&gt;, we are not using the controller that the Rails API gem exposes to us. Therefore, let&apos;s remove the gem:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;source &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;https://rubygems.org&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ruby &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;2.2.2&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;rails&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;4.2.1&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# gem &apos;rails-api&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;sqlite3&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;puma&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;oj&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gem &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;oj_mimic_json&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, the Rails API gem did other interesting things under the hood, such as disabling some unnecessary Rails middleware. Since we removed it, we now need to do so ourselves. Add to &lt;code&gt;application.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;RUBY&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ApiGreenfield&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Rails::Application&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # remove unnecessary middleware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;middleware&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rack&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Sendfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;middleware&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Rack&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;MethodOverride&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;middleware&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ActionDispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Cookies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;middleware&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ActionDispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Session&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;CookieStore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    config.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;middleware&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ActionDispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Flash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running the benchmark returns the previous results, so we can safely say we don&apos;t need the Rails API gem anymore.&lt;/p&gt;
&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;We have started with a greenfield Rails project, and have gradually applied changes to improve the speed performance of a simple benchmarked application:&lt;/p&gt;
&lt;p&gt;[table]&lt;br&gt;
Version,Req/sec,Increase&lt;br&gt;
Greenfield Rails,&quot;2,138&quot;,-&lt;br&gt;
+ Rails API Gem,&quot;2,369&quot;,+11%&lt;br&gt;
+ Rails API Gem + Oj,&quot;2,475&quot;,+15%&lt;br&gt;
+ Oj + ActionController::Metal + Custom middleware,&quot;4,206&quot;,&lt;strong&gt;+97%&lt;/strong&gt;&lt;br&gt;
[/table]&lt;/p&gt;
&lt;p&gt;Overall, we experienced an increase from &lt;em&gt;2,138&lt;/em&gt; to &lt;em&gt;4,206&lt;/em&gt; req/sec, which is &lt;em&gt;doubling the initial performance&lt;/em&gt; of a greenfield Rails application.&lt;/p&gt;
&lt;p&gt;For additional boosts, you may consider caching techniques (such as partial JSON caching), which are application dependent and are therefore out of scope here.&lt;/p&gt;
&lt;p&gt;Happy API&apos;ing!&lt;/p&gt;
</content:encoded></item><item><title>GIN: a JSON-API framework in Lua</title><link>https://www.ostinelli.net/gin-a-json-api-framework-in-lua/</link><guid isPermaLink="true">https://www.ostinelli.net/gin-a-json-api-framework-in-lua/</guid><description>GIN is a fast, low-latency, low-memory footprint, web JSON-API framework with Test Driven Development helpers and patterns. It is a framework that I open sourced some time ago, as an experiment. It all started when I heard so many good things about Lua that I wanted to see it in action and find a project where I could unleash its power. Being an API fan, it…</description><pubDate>Thu, 18 Jun 2015 12:03:53 GMT</pubDate><content:encoded>&lt;p&gt;GIN is a fast, low-latency, low-memory footprint, web JSON-API framework with Test Driven Development helpers and patterns. It is a framework that I open sourced some time ago, as an experiment. &lt;/p&gt;
&lt;p&gt;It all started when I heard so many good things about &lt;a href=&quot;http://www.lua.org/&quot;&gt;Lua&lt;/a&gt; that I wanted to see it in action and find a project where I could unleash its power. Being an API fan, it came natural for me to build a JSON-API server framework. And GIN was born.&lt;/p&gt;
&lt;p&gt;GIN is currently in its early stage, but it already enables fast development, TDD and ease of maintenance. It is helpful when you need an extra-boost in performance and scalability, since it is entirely written in &lt;a href=&quot;http://www.lua.org/&quot;&gt;Lua&lt;/a&gt; and it runs embedded in a packaged version of nginx called &lt;a href=&quot;http://openresty.org/&quot;&gt;OpenResty&lt;/a&gt;. For those not familiar with Lua, don&apos;t let that scare you away: Lua is really easy to use, very fast and simple to get started with.&lt;/p&gt;
&lt;h3 id=&quot;controllers&quot;&gt;Controllers&lt;/h3&gt;
&lt;p&gt;The syntax of a controller is extremely simple. For instance, a simple controller that returns an application&apos;s version information looks like:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;LUA&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;lua&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; InfoController &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; InfoController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { id &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;my_api&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, description &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;An API server powered by GIN.&apos; &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; InfoController&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The return statement specifies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The HTTP code 200&lt;/li&gt;
&lt;li&gt;The body of the response, which gets encoded by GIN into JSON as:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;code-caption&quot;&gt;JAVASCRIPT&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;my_api&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;description&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;An API server powered by GIN.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most of standard JSON-API paradigms are already embedded in GIN.&lt;/p&gt;

&lt;h3 id=&quot;versioning&quot;&gt;Versioning&lt;/h3&gt;
&lt;p&gt;For instance, Versioning is extremely simple. Major versioning is baked into GIN. Based on directory naming conventions, the controllers that correspond to the versioning specified in the header will be called by GIN automatically. Gin uses the HTTP header &lt;em&gt;Accept&lt;/em&gt; to version your API. The header has the format:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;application/vnd.{application-name}.v{version}+json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So for instance, if your application name (as defined in the file &lt;em&gt;./config/application.lua&lt;/em&gt;) is &lt;em&gt;demo&lt;/em&gt;, a client trying to access the version &lt;em&gt;1&lt;/em&gt; of your API will have to send the header:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Accept: application/vnd.demo.v1+json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gin only accepts requests that provide JSON in the body, hence the &lt;em&gt;+json&lt;/em&gt; portion of the Accept header.&lt;/p&gt;
&lt;h3 id=&quot;routing&quot;&gt;Routing&lt;/h3&gt;
&lt;p&gt;Routing is very easy, too. For instance, this is an example of a routing file that handles multiple versions:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;LUA&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;lua&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; routes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;gin.core.routes&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;-- define version 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; v1 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; routes.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;-- define routes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { controller &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, action &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;index&quot; &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { controller &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, action &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;create&quot; &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;-- define version 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; v2 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; routes.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;-- define routes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { controller &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, action &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;index&quot; &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { controller &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, action &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;create&quot; &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;v2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/users/:id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, { controller &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, action &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;show&quot; &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; routes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;errors&quot;&gt;Errors&lt;/h3&gt;
&lt;p&gt;Moreover, Errors are defined globally at application level. This allows to keep track of error numbering and descriptions in a single file. For example, an error file is defined as:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;LUA&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;lua&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Errors &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { status &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 400&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, message &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Invalid request.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, headers &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;X-Header&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;header&quot; &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Errors&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The global variable Errors contains the entries for all possible errors of your application. Every item in this table defines an error, where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The 1000 key is the error number.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;status&lt;/em&gt; (required): is the HTTP status code.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;message&lt;/em&gt; (required): is the error description.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;headers&lt;/em&gt; (optional): are the additional headers to be returned in the response.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When this is defined, then raising these errors from a controller is as simple as calling:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;LUA&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;lua&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;raise_error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As per this example, this will return a HTTP status 400, with the specified headers and the JSON body:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;JAVASCRIPT&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;code&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;message&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Invalid request.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;
&lt;p&gt;However, this wouldn&apos;t be a complete framework if it didn&apos;t provide an easy way to test your application. The main testing framework embedded in GIN is &lt;a href=&quot;http://olivinelabs.com/busted/&quot;&gt;Busted&lt;/a&gt;, which has an &lt;a href=&quot;http://rspec.info/&quot;&gt;RSpec&lt;/a&gt;-like syntax. If you ever used &lt;a href=&quot;http://pivotal.github.io/jasmine/&quot;&gt;Jasmine&lt;/a&gt; you&apos;ll feel right at home. In addition, Gin provides test helpers for you to use.&lt;/p&gt;
&lt;p&gt;Controller Tests in Gin are actually integration tests. An instance of OpenResty nginx will be started and a real request will be issued to a test server. The main Gin test helper you&apos;ll need to test Controllers is the method &lt;em&gt;hit&lt;/em&gt;, that will perform the integration test for you.&lt;/p&gt;
&lt;p&gt;Here&apos;s an example of a controller test (file located in &lt;em&gt;./spec/controllers/1/info_controller_spec.lua&lt;/em&gt;), that is a valid test for the &lt;em&gt;InfoController&lt;/em&gt; shown here above:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;LUA&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;lua&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;spec.spec_helper&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;describe&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;InfoController&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    describe&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;#root&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        it&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;responds with application info&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            local&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; hit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                method &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;GET&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                path &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            assert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;are&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;same&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, response.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            assert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;are&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;same&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ id &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;my_api&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, description &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;An API server powered by GIN.&apos; &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, response.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;others&quot;&gt;Others&lt;/h3&gt;
&lt;p&gt;GIN also has models and support for multiple databases, and includes a migration engine. Furthermore, it is packed with a lot of other features, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An API Console (which allows you to try out your API from a web interface).&lt;/li&gt;
&lt;li&gt;Support for multiple environments.&lt;/li&gt;
&lt;li&gt;A client console.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;alright-i-want-to-see-it&quot;&gt;Alright, I want to see it!&lt;/h3&gt;
&lt;p&gt;GIN main website is &lt;a href=&quot;http://gin.io&quot;&gt;gin.io&lt;/a&gt;, where you&apos;ll find full documentation, and even a &lt;a href=&quot;http://gin.io/tutorial.html&quot;&gt;full tutorial&lt;/a&gt; on how to Test Drive your Development with GIN. Full code is available on &lt;a href=&quot;https://github.com/ostinelli/gin&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Would this be worthy more than a simple experiment?&lt;/p&gt;
</content:encoded></item><item><title>A comparison between Misultin, Mochiweb, Cowboy, NodeJS and Tornadoweb</title><link>https://www.ostinelli.net/a-comparison-between-misultin-mochiweb-cowboy-nodejs-and-tornadoweb/</link><guid isPermaLink="true">https://www.ostinelli.net/a-comparison-between-misultin-mochiweb-cowboy-nodejs-and-tornadoweb/</guid><description>As some of you already know, I&apos;m the author of Misultin, an Erlang HTTP lightweight server library. I&apos;m interested in HTTP servers, I spend quite some time trying them out and am always interested in comparing them from different perspectives. Today I wanted to try the same benchmark against various HTTP server libraries: Misultin (Erlang) Mochiweb (Erlang)…</description><pubDate>Mon, 09 May 2011 03:19:08 GMT</pubDate><content:encoded>&lt;p&gt;As some of you already know, I&apos;m the author of Misultin, an Erlang HTTP lightweight server library. I&apos;m interested in HTTP servers, I spend quite some time trying them out and am always interested in comparing them from different perspectives.&lt;/p&gt;
&lt;p&gt;Today I wanted to try the same benchmark against various HTTP server libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ostinelli/misultin&quot;&gt;Misultin&lt;/a&gt; (Erlang)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mochi/mochiweb&quot;&gt;Mochiweb&lt;/a&gt; (Erlang)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/extend/cowboy&quot;&gt;Cowboy&lt;/a&gt; (Erlang)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot;&gt;NodeJS&lt;/a&gt; (V8)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.tornadoweb.org/&quot;&gt;Tornadoweb&lt;/a&gt; (Python)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&apos;ve chosen these libraries because they are the ones which currently interest me the most. Misultin, obviously since I wrote it; Mochiweb, since it&apos;s a very solid library widely used in production (afaik it has been used or is still used to empower the Facebook Chat, amongst other things); Cowboy, a newly born lib whose programmer is very active in the Erlang community; NodeJS, since bringing javascript to the backend has opened up a new whole world of possibilities (code reusable in frontend, ease of access to various programmers,...); and finally, Tornadoweb, since Python still remains one of my favourites languages out there, and Tornadoweb has been excelling in loads of benchmarks and in production, empowering FriendFeed.&lt;/p&gt;

&lt;p&gt;Two main ideas are behind this benchmark. First, I did not want to do a &quot;Hello World&quot; kind of test: we have static servers such as &lt;a href=&quot;http://nginx.org/&quot;&gt;Nginx&lt;/a&gt; that wonderfully perform in such tasks. This benchmark needed to address dynamic servers. Second, I wanted sockets to get periodically closed down, since having all the load on a few sockets scarcely correspond to real life situations.&lt;/p&gt;
&lt;p&gt;For the latter reason, I decided to use a &lt;a href=&quot;http://gom-jabbar.org/articles/2009/02/04/httperf-and-file-descriptors&quot;&gt;patched version&lt;/a&gt; of &lt;a href=&quot;http://www.hpl.hp.com/research/linux/httperf/&quot;&gt;HttPerf&lt;/a&gt;. It&apos;s a widely known and used benchmark tool from HP, which basically tries to send a desired number of requests out to a server and reports how many of these actually got replied, and how many errors were experienced in the process (together with a variety of other pieces of information). A great thing about HttPerf is that you can set a parameter, called &lt;em&gt;--num-calls&lt;/em&gt;, which sets the amount of calls per session (i.e. socket connection) before the socket gets closed by the client. The command issued in these tests was:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;httperf --timeout=5 --client=0/1 --server= --port=8080 --uri=/?value=benchmarks --rate= --send-buffer=4096&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        --recv-buffer=16384 --num-conns=5000 --num-calls=10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value of rate has been set incrementally between 100 and 1,200. Since the number of requests/sec = &lt;em&gt;rate&lt;/em&gt; * &lt;em&gt;num-calls&lt;/em&gt;, the tests were conducted for a desired number of responses/sec incrementing from 1,000 to 12,000. The total number of requests = &lt;em&gt;num-conns&lt;/em&gt; * &lt;em&gt;rate&lt;/em&gt;, which has therefore been a fixed value of 50,000 along every test iteration.&lt;/p&gt;
&lt;p&gt;The test basically asks servers to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;check if a GET variable is set&lt;/li&gt;
&lt;li&gt;if the variable is not set, reply with an XML stating the error&lt;/li&gt;
&lt;li&gt;if the variable is set, echo it inside an XML&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Therefore, what is being tested is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;headers parsing&lt;/li&gt;
&lt;li&gt;querystring parsing&lt;/li&gt;
&lt;li&gt;string concatenation&lt;/li&gt;
&lt;li&gt;sockets implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The server is a virtualized up-to-date Ubuntu 10.04 LTS with 2 CPU and 1.5GB of RAM. Its &lt;em&gt;/etc/sysctl.conf&lt;/em&gt; file has been tuned with these parameters:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;BASH&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Maximum TCP Receive Window&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.core.rmem_max&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 33554432&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Maximum TCP Send Window&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.core.wmem_max&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 33554432&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# others&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.ipv4.tcp_rmem&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 4096&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 16384&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 33554432&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.ipv4.tcp_wmem&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 4096&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 16384&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 33554432&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.ipv4.tcp_syncookies&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# this gives the kernel more memory for tcp which you need with many (100k+) open socket connections&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.ipv4.tcp_mem&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 786432&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1048576&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 26777216&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.ipv4.tcp_max_tw_buckets&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 360000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.core.netdev_max_backlog&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2500&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;vm.min_free_kbytes&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 65536&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;vm.swappiness&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.ipv4.ip_local_port_range&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1024&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 65535&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net.core.somaxconn&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 65535&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;/etc/security/limits.conf&lt;/em&gt; file has been tuned so that ulimit -n is set to 65535 for both hard and soft limits.&lt;/p&gt;
&lt;p&gt;Here is the code for the different servers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Misultin&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;misultin_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Port) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    misultin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Port}, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    misultin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % get value parameter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Args &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;parse_qs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; misultin_utility&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get_key_value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Args),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}], [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;no value specified&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        _&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}], [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Value, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Mochiweb&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;mochi_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Port) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    mochiweb_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Port}, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    mochiweb_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % get value parameter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Args &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;parse_qs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; misultin_utility&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get_key_value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Args),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;respond&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}], [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;no value specified&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        _&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;respond&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}], [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Value, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: i&apos;m using misultin_utility:get_key_value/2 function inside this code since proplists:get_value/2 is much slower.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cowboy&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cowboy_bench&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Port) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cowboy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Dispatch &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        %% {Host, list({Path, Handler, Opts})}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;_&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;_&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cowboy_bench_handler&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []}]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    %% Name, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    cowboy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_listener&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        cowboy_tcp_transport&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Port}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        cowboy_http_protocol&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Dispatch}]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    application&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cowboy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cowboy_bench_handler&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;behaviour&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cowboy_http_handler&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;terminate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;tcp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, Req, _Opts) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Req, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined_state&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req, State) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Req2} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; case&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cowboy_http_req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;qs_val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&amp;gt;, Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            cowboy_http_req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [{&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&amp;gt;}], &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;no value specified&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&amp;gt;, Req);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {Value, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            cowboy_http_req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [{&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&amp;gt;}], [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Value, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], Req)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Req2, State}.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;terminate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(_Req, _State) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;NodeJS&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;JAVASCRIPT&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; http &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;http&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;), url &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;url&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;createServer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    response.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;writeHead&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; urlObj &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; url.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request.url, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; urlObj.query[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        response.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;no value specified&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        response.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;listen&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8080&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Tornadoweb&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;PYTHON&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tornado.ioloop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tornado.web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MainHandler&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tornado&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;web&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RequestHandler&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.get_argument(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;value&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.set_header(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;text/xml&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.write(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;no value specified&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.write(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;application &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tornado.web.Application([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, MainHandler),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __name__&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;__main__&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    application.listen(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;8080&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    tornado.ioloop.IOLoop.instance().start()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I took this code and run it against:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Misultin 0.7.1 (Erlang R14B02)&lt;/li&gt;
&lt;li&gt;Mochiweb 1.5.2 (Erlang R14B02)&lt;/li&gt;
&lt;li&gt;Cowboy master 420f5ba (Erlang R14B02)&lt;/li&gt;
&lt;li&gt;NodeJS 0.4.7&lt;/li&gt;
&lt;li&gt;Tornadoweb 1.2.1 (Python 2.6.5)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All the libraries have been run with the standard settings. Erlang was launched with Kernel Polling enabled, and with SMP disabled so that a single CPU was used by all the libraries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test results&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The raw printout of HttPerf results that I got can be downloaded from &lt;a href=&quot;/media/2011/05/results.zip&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/2011/05/desired_vs_real.jpg&quot; alt=&quot;&quot; title=&quot;desired_vs_real&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/2011/05/errors.jpg&quot; alt=&quot;&quot; title=&quot;errors&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/2011/05/response_times_log.jpg&quot; alt=&quot;&quot; title=&quot;response_times_log&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: the above graph has a logarithmic Y scale.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/2011/05/response_count.jpg&quot; alt=&quot;&quot; title=&quot;response_count&quot;&gt;&lt;/p&gt;
&lt;p&gt;According to this, we see that &lt;strong&gt;Tornadoweb&lt;/strong&gt; tops at around 1,500 responses/seconds, &lt;strong&gt;NodeJS&lt;/strong&gt; at 3,000, &lt;strong&gt;Mochiweb&lt;/strong&gt; at 4,850, &lt;strong&gt;Cowboy&lt;/strong&gt; at 8,600 and &lt;strong&gt;Misultin&lt;/strong&gt; at 9,700. While Misultin and Cowboy experience very little or no error at all, the other servers seem to funnel under the load. Please note that &quot;Errors&quot; are timeout errors (over 5 seconds without a reply). Total responses and response times speak for themselves.&lt;/p&gt;
&lt;p&gt;I have to say that I&apos;m surprised on these results, to the point I&apos;d like to have feedback on code and methodology, with alternate tests that can be performed. Any input is welcome, and I&apos;m available to update this post and correct eventual errors I&apos;ve made, as an ongoing discussion with whomever wants to contribute.&lt;/p&gt;
&lt;p&gt;However, please do refrain from flame wars which are not welcomed here. I have published this post exactly because I was surprised on the results I got.&lt;/p&gt;
&lt;p&gt;What is your opinion on all this?&lt;/p&gt;
&lt;p&gt;-----------------------------------------------------&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE (May 16th, 2011)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Due to the success of these benchmarks I want to stress an important point when you read any of these (including mines).&lt;/p&gt;
&lt;p&gt;Benchmarks often are misleading interpreted as &quot;the higher you are on a graph, the best that &lt;em&gt;*lib-of-the-moment-name-here*&lt;/em&gt; is at doing everything&quot;. This is absolutely the wrongest way to look at those. I cannot stress this point enough.&lt;/p&gt;
&lt;p&gt;&apos;Fast&apos; is only 1 of the &apos;n&apos; features you desire from a webserver library: you definitely want to consider stability, features, ease of maintenance, low standard deviation, code usability, community, developments speed, and many other factors whenever choosing the best suited library for your own application. There is no such thing as generic benchmarks. These ones are related to a very specific situation: fast application computational times, loads of connections, and small data transfer.&lt;/p&gt;
&lt;p&gt;Therefore, please use this with a grain of salt and do not jump to generic conclusions regarding any of the cited libraries, which as I&apos;ve clearly stated in the beginning of my post I all find interesting and valuable. And I still am very open in being criticized for the described methodology or other things I might have missed.&lt;/p&gt;
</content:encoded></item><item><title>Misultin: erlang and websockets</title><link>https://www.ostinelli.net/misultin-erlang-and-websockets/</link><guid isPermaLink="true">https://www.ostinelli.net/misultin-erlang-and-websockets/</guid><description>Inspired by Joe Armstrong&apos;s post, I&apos;ve recently added websocket support to misultin v0.4, my Erlang library for building fast lightweight HTTP servers. Basically, websockets allow a two-way asynchronous communication between browser and servers, filling the gap that some technologies such as ajax and comet have tried to fulfill in these recent years. If you…</description><pubDate>Wed, 20 Jan 2010 15:33:12 GMT</pubDate><content:encoded>&lt;p&gt;Inspired by Joe Armstrong&apos;s &lt;a href=&quot;http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html&quot;&gt;post&lt;/a&gt;, I&apos;ve recently added &lt;a href=&quot;http://dev.w3.org/html5/websockets/&quot;&gt;websocket&lt;/a&gt; support to &lt;a href=&quot;http://code.google.com/p/misultin/&quot;&gt;misultin&lt;/a&gt; v0.4, my Erlang library for building fast lightweight HTTP servers.&lt;/p&gt;
&lt;p&gt;Basically, websockets allow a two-way asynchronous communication between browser and servers, filling the gap that some technologies such as ajax and comet have tried to fulfill in these recent years. If you want to try this out yourself, you will first need to grab a browser which implements websockets, such as &lt;a href=&quot;http://www.google.com/chrome/&quot;&gt;Google Chrome&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The typical html page with javascript code to use websockets is as follows:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;JAVASCRIPT&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;         function addStatus(text){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            var date &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            document.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;status&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).innerHTML &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;status&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).innerHTML&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;               +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; date &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;: &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; text &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&amp;lt;br&amp;gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;         }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;         function ready(){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;WebSocket&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; window) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;               // browser supports websockets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;               var ws &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; WebSocket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ws://localhost:8080/service&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;               ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;onopen&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                  // websocket is connected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                  addStatus&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;websocket connected!&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                  // send hello data to server.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                  ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;hello server!&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                  addStatus&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;sent message to server: &apos;hello server&apos;!&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;               };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;               ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;onmessage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;evt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                  var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; receivedMsg &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; evt.data;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                  addStatus&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;server sent the following: &apos;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; receivedMsg &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&apos;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;               };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;               ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;onclose&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                  // websocket was closed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;                  addStatus&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;websocket was closed&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;               };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            } else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;               // browser does not support websockets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;               addStatus&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;sorry, your browser does not support websockets.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;         }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; onload&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ready();&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s the code to use misultin to handle the requests of this script:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-module(misultin_websocket_example).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-export([start/1, stop/0]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;% start misultin http server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;start(Port) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    misultin:start_link([{port, Port}, {loop, fun(Req) -&amp;gt; handle_http(Req, Port) end},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {ws_loop, fun(Ws) -&amp;gt; handle_websocket(Ws) end}]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;% stop misultin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;stop() -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    misultin:stop().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;% callback on request received&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;handle_http(Req, Port) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    % output&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Req:ok([]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;% callback on received websockets data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;handle_websocket(Ws) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        {browser, Data} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            Ws:send([&quot;received &apos;&quot;, Data, &quot;&apos;&quot;]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            handle_websocket(Ws);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        _Ignore -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            handle_websocket(Ws)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    after 5000 -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Ws:send(&quot;pushing!&quot;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        handle_websocket(Ws)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    end.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;handle_websocket/1 is spawned by misultin to handle the connected websockets. Data coming from a browser will be sent to this process and will have the message format {browser, Data}, where Data is a string(). If you need to send data to the browser, you may do so by using the parametrized function Ws:send(Data), Data being a string() or an iolist().&lt;/p&gt;
&lt;p&gt;Compile and run the example here above with misultin_websocket_example:start(8080). Then, open up your Chrome (or other websocket compliant browser) and point it to an .html file containing the above code.&lt;/p&gt;
&lt;p&gt;You should normally see this being gradually printed on your browser:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wed Jan 20 2010 15:18:52 GMT+0100 (CET): websocket connected!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wed Jan 20 2010 15:18:52 GMT+0100 (CET): sent message to server: &apos;hello server&apos;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wed Jan 20 2010 15:18:52 GMT+0100 (CET): server sent the following: &apos;received &apos;hello server!&apos;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wed Jan 20 2010 15:18:57 GMT+0100 (CET): server sent the following: &apos;pushing!&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wed Jan 20 2010 15:19:02 GMT+0100 (CET): server sent the following: &apos;pushing!&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wed Jan 20 2010 15:19:07 GMT+0100 (CET): server sent the following: &apos;pushing!&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In normal environments you may consider serving the .html page from misultin directly. You may do so with the following and complete misultin module:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;misultin_websocket_example&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% start misultin http server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Port) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;   misultin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Port}, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req, Port) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ws_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Ws) -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_websocket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Ws) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% stop misultin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;   misultin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% callback on request received&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req, Port) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;   % output&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/html&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;   &amp;lt;html&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &amp;lt;head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;         &amp;lt;script type=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;text/javascript&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            function addStatus(text){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;               var date = new Date();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;               document.getElementById(&apos;status&apos;).innerHTML = document.getElementById(&apos;status&apos;).innerHTML&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  + date + &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; + text + &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;lt;br&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            function ready(){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;               if (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;WebSocket&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in window) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  // browser supports websockets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  var ws = new WebSocket(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ws://localhost:&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;integer_to_list&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Port) ,&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/service&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  ws.onopen = function() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     // websocket is connected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     addStatus(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;websocket connected!&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     // send hello data to server.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     ws.send(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;hello server!&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     addStatus(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;sent message to server: &apos;hello server&apos;!&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  ws.onmessage = function (evt) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     var receivedMsg = evt.data;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     addStatus(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;server sent the following: &apos;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; + receivedMsg + &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  ws.onclose = function() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     // websocket was closed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                     addStatus(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;websocket was closed&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;               } else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  // browser does not support websockets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                  addStatus(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;sorry, your browser does not support websockets.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;               }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;         &amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &amp;lt;body onload=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ready();&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;         &amp;lt;div id=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      &amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;   &amp;lt;/html&amp;gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% callback on received websockets data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_websocket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Ws) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;   receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;browser&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Data} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;         Ws:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;received &apos;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Data, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;         handle_websocket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Ws);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      _Ignore -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;         handle_websocket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Ws)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;   after&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 5000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      Ws:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;pushing!&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      handle_websocket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Ws)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;   end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please note that the &lt;a href=&quot;http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-68&quot;&gt;Websocket Protocol&lt;/a&gt; still is draft. use with caution.&lt;/p&gt;
</content:encoded></item><item><title>Misultin library</title><link>https://www.ostinelli.net/misultin/</link><guid isPermaLink="true">https://www.ostinelli.net/misultin/</guid><description>Today I&apos;ve released Misultin (pronounced mee-sul-teen), an Erlang library for building fast lightweight HTTP servers. The first benchmarks are quite satisfying, even though there still is work to do. Here is the simple code for Misultin&apos;s Hello World. ERLANG-module(misultin_hello_world). -vsn(&apos;0.1&apos;). -export([start/1, stop/0, handle_http/1]). % start…</description><pubDate>Mon, 27 Jul 2009 12:11:47 GMT</pubDate><content:encoded>&lt;p&gt;Today I&apos;ve released Misultin (pronounced mee-sul-teen), an Erlang library for building fast lightweight HTTP servers. The first &lt;a href=&quot;http://code.google.com/p/misultin/wiki/Benchmarks&quot;&gt;benchmarks&lt;/a&gt; are quite satisfying, even though there still is work to do.&lt;/p&gt;
&lt;p&gt;Here is the simple code for Misultin&apos;s Hello World.&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;misultin_hello_world&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;vsn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;0.1&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% start misultin http server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Port) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    misultin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Port}, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% stop misultin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    misultin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% callback on request received&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hello World.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&apos;s the code to echo a GET variable in a XML form.&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;misultin_get_variable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;vsn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;0.1&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% start misultin http server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Port) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    misultin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Port}, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}]).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% stop misultin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    misultin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% callback on request received&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_http&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Req) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % get params&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Args &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;parse_qs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; proplists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get_value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Args),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        undefined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}], &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;no value specified&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        _&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            Req:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}], &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~s&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [Value])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Available also are &lt;a href=&quot;http://code.google.com/p/misultin/wiki/ExamplesPage&quot;&gt;additional code examples&lt;/a&gt;, and the &lt;a href=&quot;http://code.google.com/p/misultin/wiki/Exports&quot;&gt;full list of exports&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You may find Misultin, released under the &lt;a href=&quot;http://www.opensource.org/licenses/bsd-license.php&quot;&gt;New BSD License&lt;/a&gt;, on its &lt;a href=&quot;http://code.google.com/p/misultin&quot;&gt;project page on Google code&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Boost message passing between Erlang nodes</title><link>https://www.ostinelli.net/boost-message-passing-between-erlang-nodes/</link><guid isPermaLink="true">https://www.ostinelli.net/boost-message-passing-between-erlang-nodes/</guid><description>Message passing between Erlang nodes is considerably slower than within the same node. This is normal, and is due to the fact that messages sent between nodes are actually copied from the area of the sender to that of the receiver, then sent over from one node to the other via TCP/IP. I was getting interested when a server could achieve amazing performance…</description><pubDate>Tue, 07 Apr 2009 22:43:31 GMT</pubDate><content:encoded>&lt;p&gt;Message passing between Erlang nodes is considerably slower than within the same node. This is normal, and is due to the fact that messages sent between nodes are actually &lt;strong&gt;copied&lt;/strong&gt; from the area of the sender to that of the receiver, then sent over from one node to the other via TCP/IP.&lt;/p&gt;
&lt;p&gt;I was getting interested when a server could achieve amazing performance over a single node, performance which got much lower once the server got distributed over two Erlang nodes. I therefore tried a small benchmark test to somehow measure the difference in message passing speed within/across Erlang nodes.&lt;/p&gt;

&lt;p&gt;The machine used in this benchmark is an apple macbook running Leopard, with 2.0GHz Intel Core 2 Duo and 2GB of DDR3 RAM memory.&lt;/p&gt;
&lt;p&gt;This benchmark is a very simple ping request/pong response test. A process &apos;A&apos; sends a ping message to process &apos;B&apos;, which replies with a pong message.&lt;/p&gt;
&lt;p&gt;Code for the &lt;strong&gt;pong process&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% starts pong&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;flood_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;spawn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pong_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pong_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {{Sender, SenderNode}, Any} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            % pong back&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            {Sender, SenderNode} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Any},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            pong_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        shutdown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;pong shutdown&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,[]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        _Ignore -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            pong_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    after&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 60000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;pong timeout, shutdown&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,[])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This very simple code basically starts a process and registers it with the name &lt;em&gt;flood_pong&lt;/em&gt;. You can see that to any request with format:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{Sender, SenderNode}, Any}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;flood_pong will reply with a message with format:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Any}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code for the &lt;strong&gt;ping process&lt;/strong&gt;, i.e. the one that starts the ping requests, is the following:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% start ping&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PongNode, Num) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;flood_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;spawn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), Num) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PongNode, Num).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(_PongNode, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PongNode, Num) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % send a spawned ping&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    spawn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;flood_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, PongNode} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;flood_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()}, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ping_request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PongNode, Num &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, Start, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    T &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; timer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now_diff&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), Start),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;RECEIVED ALL &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ms [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/min]&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,[Num, T, (Num&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;60000000&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;T)]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, Start, Count) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, _PingBack} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, Start, Count&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        _Received -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, Start, Count)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    after&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ping timeout, missing &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; pong, shutdown&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,[Count])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code does two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Starts and registers a &lt;em&gt;flood_ping&lt;/em&gt; process, which will be responsible to await and count the incoming pong replies. This allows it to compute the time needed for all the pong replies to get back to the node where the ping requests where first sent.&lt;/li&gt;
&lt;li&gt;Spawns the ping requests [one process per ping request].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s give it a try. First, we have to start up two Erlang nodes, so I fire up terminal and enter:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;BASH&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; roberto&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;erl&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; +K&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; +P&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 500000&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -name&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;one@rob.loc&apos;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -setcookie&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; asd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and in another terminal window:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;BASH&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; roberto&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;erl&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; +K&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; +P&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 500000&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -name&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;two@rob.loc&apos;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -setcookie&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; asd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This initializes two erlang nodes, &apos;&lt;a href=&quot;mailto:one@rob.loc&quot;&gt;one@rob.loc&lt;/a&gt;&apos; and &apos;&lt;a href=&quot;mailto:two@rob.loc&quot;&gt;two@rob.loc&lt;/a&gt;&apos;, both with kernel polling enabled and a maximum number of processes per node set to 500,000.&lt;/p&gt;
&lt;p&gt;I need to ensure that the nodes can see each other, so from &apos;&lt;a href=&quot;mailto:one@rob.loc&quot;&gt;one@rob.loc&lt;/a&gt;&apos; I ping &apos;&lt;a href=&quot;mailto:two@rob.loc&quot;&gt;two@rob.loc&lt;/a&gt;&apos;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;one@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;net_adm&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;two@rob.loc&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pong&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;one@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nodes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;two@rob.loc&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&apos;s perform a message passing speed benchmark for messages sent and received within the same Erlang node. First, I start up the pong process:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;one@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; flood1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I then need to start the ping requests, and I do so by issuing the start_ping/2 function, which has per arguments the name of the recipient node of the ping requests, and the number of requests to be performed. I therefore set the first parameter to node() and the second to 200,000 [we&apos;ll always try out 200,000 ping requests].&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;one@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; flood1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;RECEIVED ALL &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200000&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2257727&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5315080.166911234&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I see therefore that &lt;strong&gt;within the same Erlang node&lt;/strong&gt;, this benchmark gives a result of an average of &lt;strong&gt;5.3 million&lt;/strong&gt; ping/pong messages per minute. Quite a rush.&lt;/p&gt;
&lt;p&gt;Let&apos;s now try the same thing with pong running on &apos;&lt;a href=&quot;mailto:two@rob.loc&quot;&gt;two@rob.loc&lt;/a&gt;&apos;, and ping requests coming from &apos;&lt;a href=&quot;mailto:one@rob.loc&quot;&gt;one@rob.loc&lt;/a&gt;&apos;. I start the pong process on &apos;&lt;a href=&quot;mailto:two@rob.loc&quot;&gt;two@rob.loc&lt;/a&gt;&apos;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;two@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; flood1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I issue the ping request from &apos;&lt;a href=&quot;mailto:one@rob.loc&quot;&gt;one@rob.loc&lt;/a&gt;&apos;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;one@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; flood1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;two@rob.loc&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;RECEIVED ALL &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200000&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 16727643&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;717375.4246189974&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I see therefore that &lt;strong&gt;on two different Erlang nodes&lt;/strong&gt;, this benchmark gives a result of an average of &lt;strong&gt;700 thousands&lt;/strong&gt; ping/pong messages per minute.&lt;/p&gt;
&lt;p&gt;This is around 7 times a loss in performance when compared to the same benchmark run on a single Erlang node. This is to be expected, still it does mean that a system heavily dependant on message passing and running on a single Erlang node would be considerably faster than one running on distributed nodes (one of the things Erlang is great at doing).&lt;/p&gt;
&lt;p&gt;At this point, I tried reducing the overhead in message passing, by using UDP instead of Erlang&apos;s native functionalities. This was no success at all, UDP having all the troubles it&apos;s known for (packet loss, ordering, double packet sending, ...) without me getting any interesting speed improvement.&lt;/p&gt;
&lt;p&gt;So I got this thought: what if Erlang&apos;s message passing overhead is so demanding, due to TCP/IP, that actually &lt;em&gt;queuing&lt;/em&gt; messages sent to processes running on the same node and sending them altogether would increase the overall passing speed? TCP/IP already does provide such mechanisms, but what if performing this queuing at Erlang application level could bring significant improvements to infra-nodes message passing?&lt;/p&gt;
&lt;p&gt;This is the picture. On both Erlang nodes I run a gen_server (which I called &lt;em&gt;qr)&lt;/em&gt; which performs queuing and routing of messages sent from one node to the other. Instead of sending messages directly from a process A on node &apos;&lt;a href=&quot;mailto:one@rob.loc&quot;&gt;one@rob.loc&lt;/a&gt;&apos; to a process B on node &apos;&lt;a href=&quot;mailto:two@rob.loc&quot;&gt;two@rob.loc&lt;/a&gt;&apos;, process A sends a routing request to the &lt;em&gt;qr&lt;/em&gt; running on &apos;&lt;a href=&quot;mailto:one@rob.loc&quot;&gt;one@rob.loc&lt;/a&gt;&apos;, which will then send it to the &lt;em&gt;qr&lt;/em&gt; running on &apos;&lt;a href=&quot;mailto:two@rob.loc&quot;&gt;two@rob.loc&lt;/a&gt;&apos;, which will finally forward it to B. Fact is, the sending &lt;em&gt;qr&lt;/em&gt; will queue messages until a certain number of them for the same node have piled up, or a timeout period has expired.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/2009/04/qr1.gif&quot; alt=&quot;qr&quot;&gt;&lt;/p&gt;
&lt;p&gt;I start by defining the gen_server API to route a message. Here it is:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% Function() -&amp;gt; void()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% Description: Gets a routing request&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ToPid, ToNode}, Message) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ToNode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=:=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            % send directly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            ToPid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Message;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            % queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            gen_server&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cast&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;SERVER&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;queue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ToNode}, {ToPid, Message}})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that we need to pass the &lt;strong&gt;Pid&lt;/strong&gt; of the destination process, as well as the name of the &lt;strong&gt;Node&lt;/strong&gt; where this process is running, together with the &lt;strong&gt;Message&lt;/strong&gt; that we need to send.&lt;/p&gt;
&lt;p&gt;In case the node is remote, this will cast a message to &lt;em&gt;qr&lt;/em&gt;, which will handle it:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% add incoming routing request to queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_cast&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;queue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, DestNode}, {ToPid, Message}}, Queue) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % to pid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Msg &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ToPid, Message},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % get if node exists in queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;keysearch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(DestNode, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Queue) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            % add node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            NewQueue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [{DestNode, {&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), [Msg]}}|Queue];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {DestNode, {CreationTime, MsgList}}} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            % check if queue is long enough&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            case&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(MsgList) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;QUEUELENGTH&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                    % queue of a node is of maximum lenght, send routing message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    {&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;QR&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, DestNode} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;queue_route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, [Msg|MsgList]},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                    % empty queue for node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    NewQueue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;keydelete&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(DestNode, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Queue);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                    % add message to queue list and replace node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    NewQueue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;keyreplace&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(DestNode, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Queue, {DestNode, {CreationTime, [Msg|MsgList]}})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % purge timeout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    PurgedQueue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; purge_queue_selective&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(NewQueue),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;noreply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, PurgedQueue, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% Function -&amp;gt; PurgedQueue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% Description: Loop queue and purge only nodes on timeout.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;purge_queue_selective&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Queue) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % check timeout, send and remove element if needed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    FilterFun &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({DestNode, {CreationTime, MsgList}}) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; timer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now_diff&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), CreationTime) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;QUEUETIMEOUT&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                % timeout for a node, send routing message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                % io:format(&quot;send selective: {?QR, ~p} ! {queue_route, ~p}~n&quot;,[DestNode, MsgList]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                {&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;QR&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, DestNode} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;queue_route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, MsgList},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                % delete node from queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % return cleaned queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(FilterFun, Queue).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The mecanism is quite simple. When a message to be sent to a remote node arrives to &lt;em&gt;qr&lt;/em&gt;, we build a list of key tuples [which will be passed along as gen_server State variable] of format:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{DestNode, {CreationTime, MsgList}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DestNode, i.e. the destination node, is the tuple key. CreationTime is a parameter which allows to know when a timeout for the messages to DestNode has passed. MsgList is a list of tuples of the messages to be sent to DestNode, in format:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ToPid, Message}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We handle this key list to check when to send all the queued messages to the other node, which we do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;when a certain &lt;strong&gt;timeout&lt;/strong&gt; has passed for that node [computed using CreationTime];&lt;/li&gt;
&lt;li&gt;when the number of messages to be sent has reached a certain &lt;strong&gt;size&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We see that the gen_server cast also establishes an overall timeout of 200 ms, which will fire when no other messages are received by &lt;em&gt;qr&lt;/em&gt; and thus we need to send the remaining messages out. This timeout is handled with a handle_info call:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% timeout on a cast message, purge queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;timeout&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Queue) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % purge timeout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    PurgedQueue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; purge_queue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Queue),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;noreply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, PurgedQueue};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% Function -&amp;gt; PurgedQueue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% Description: Loop queue and purge all nodes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;purge_queue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Queue) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % sent to all remaining&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    FilterFun &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({DestNode, {_CreationTime, MsgList}}) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        % send routing message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;QR&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, DestNode} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;queue_route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, MsgList}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(FilterFun, Queue),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % return an empty queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [].&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we can see from here over, a message sent from a &lt;em&gt;qr&lt;/em&gt; on one node to a &lt;em&gt;qr&lt;/em&gt; of another node has format:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;queue_route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, MsgList}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With MsgList being a list of the individual messages in format:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ToPid, Message}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a &lt;em&gt;qr&lt;/em&gt; of a node receives such a message, it handles it:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle_info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;queue_route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, MsgList}, State) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    RouteFun &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ToPid, Message}) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        % local send to node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ToPid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    lists&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(RouteFun, MsgList),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;noreply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, State, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, this basically is it. Let&apos;s now see if this does improve message passing between nodes.&lt;/p&gt;
&lt;p&gt;For this, we need to redifine the pong_loop so that it does not send messages directly to the process, but routes its requests to &lt;em&gt;qr&lt;/em&gt; instead.&lt;/p&gt;
&lt;p&gt;New code for the &lt;strong&gt;pong process&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% starts pong&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;flood_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;spawn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pong_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pong_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {{Sender, SenderNode}, Any} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            % pong back&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            qr&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({Sender, SenderNode}, {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Any}),    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% &amp;lt; === ONLY LINE CHANGED ===&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            pong_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        shutdown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;pong shutdown&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,[]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        _Ignore -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            pong_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    after&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 30000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;pong timeout, shutdown&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,[])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same goes for the &lt;strong&gt;ping process&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;% start ping&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PongNode, Num) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    register&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;flood_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;spawn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), Num) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PongNode, Num).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(_PongNode, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PongNode, Num) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    % send a spawned ping                               % === \/ ONLY LINE CHANGED ===&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    spawn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;fun&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; qr&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;flood_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, PongNode}, {{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;flood_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()}, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ping_request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(PongNode, Num &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, Start, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    T &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; timer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now_diff&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), Start),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;RECEIVED ALL &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ms [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/min]&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,[Num, T, (Num&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;60000000&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;T)]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, Start, Count) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    receive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, _PingBack} -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, Start, Count&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        _Received -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            ping_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Num, Start, Count)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    after&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        io&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ping timeout, missing &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; pong, shutdown&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;~n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,[Count])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are all set. Let&apos;s try to immediately perform a test on two different Erlang nodes, pong running on &apos;&lt;a href=&quot;mailto:two@rob.loc&quot;&gt;two@rob.loc&lt;/a&gt;&apos;, and ping requests coming from &apos;&lt;a href=&quot;mailto:one@rob.loc&quot;&gt;one@rob.loc&lt;/a&gt;&apos;. I start &lt;em&gt;qr&lt;/em&gt; and the pong process on &apos;&lt;a href=&quot;mailto:two@rob.loc&quot;&gt;two@rob.loc&lt;/a&gt;&apos;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;two@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;55&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; qr&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;two@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;56&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; flood2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I start &lt;em&gt;qr&lt;/em&gt; and issue the ping request from &apos;&lt;a href=&quot;mailto:one@rob.loc&quot;&gt;one@rob.loc&lt;/a&gt;&apos;:&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;one@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;44&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; qr&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;one@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;45&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; flood2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&apos;two@rob.loc&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;RECEIVED ALL &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200000&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 5690225&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2108879.7015935224&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I see therefore that &lt;strong&gt;on two different Erlang nodes&lt;/strong&gt;, this benchmark gives a result of an average of &lt;strong&gt;2.1 million&lt;/strong&gt; ping/pong messages per minute, &lt;strong&gt;3 times as much as without message queuing&lt;/strong&gt;. This is interesting.&lt;/p&gt;
&lt;p&gt;Just to be on the safe side, I try the same benchmark for messages sent via &lt;em&gt;qr&lt;/em&gt; to processes running on the same Erlang node.&lt;/p&gt;
&lt;div class=&quot;code-caption&quot;&gt;ERLANG&lt;/div&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;erlang&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;two@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; flood2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_pong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;two@rob&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loc&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;51&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; flood2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start_ping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;RECEIVED ALL &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200000&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2264539&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5299091.779828035&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I see therefore that &lt;strong&gt;within the same Erlang node&lt;/strong&gt;, this benchmark gives a result of an average of &lt;strong&gt;5.3 million&lt;/strong&gt; ping/pong messages per minute, the same that we had without the queuing mechanism.&lt;/p&gt;
&lt;p&gt;To summarize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;without&lt;/strong&gt; queuing mechanism:
&lt;ul&gt;
&lt;li&gt;same Erlang node: 5.3 million messages/min;&lt;/li&gt;
&lt;li&gt;different Erlang nodes: &lt;strong&gt;700 K&lt;/strong&gt; messages/min.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;with&lt;/strong&gt; queuing mechanism:
&lt;ul&gt;
&lt;li&gt;same Erlang node: 5.3 million messages/min;&lt;/li&gt;
&lt;li&gt;different Erlang nodes: &lt;strong&gt;2.1 million&lt;/strong&gt; messages/min.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The complete code to run this on your machine is available &lt;a href=&quot;/media/2009/04/erlang_mq_boost.zip&quot;&gt;here&lt;/a&gt;. This whole &apos;queuing idea&apos; is still an experiment, and I&apos;d be more than delighted to hear your feedback, to see whether you are getting the same results, you know how to improve the concept or the code, or you have any considerations at all you would like to share.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;UPDATE [April 17th, 2009]&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Due to a comment here below from &lt;a href=&quot;http://adam.bregenzer.net/&quot;&gt;Adam Bregenzer&lt;/a&gt;, who performed a test on a Linux box and had very different results, I&apos;ve decided to perform some testing on 3 different OS. Here is a summary of these tests, but please bear in mind that these results are definitely non exhaustive.&lt;/p&gt;
&lt;p&gt;1. macbook running &lt;strong&gt;Leopard OSX&lt;/strong&gt;, with 2.0GHz Intel Core 2 Duo and 2GB of DDR3 RAM memory.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on the same Erlang node: 5.3 million messages/min;&lt;/li&gt;
&lt;li&gt;on different Erlang nodes:
&lt;ul&gt;
&lt;li&gt;without queuing mechanism: 700 K messages/min.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;with queuing mechanism: 2.1 million messages/min&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2. &lt;strong&gt;Ubuntu 8.10 Linux&lt;/strong&gt;, 64-bit system with 2.5GHz Intel Core 2 Duo [Adam&apos;s test]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on the same Erlang node: 11.7 million messages/min;&lt;/li&gt;
&lt;li&gt;on different Erlang nodes:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;without queuing mechanism: 4.8 million messages/min.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;with queuing mechanism: 3.6 million messages/min.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3. &lt;strong&gt;Ubuntu 9.04 beta Linux&lt;/strong&gt;, 32-bit system on a VM with 1 CPU 2.0GHz and 512MB of RAM memory.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on the same Erlang node: 4.6 million messages/min;&lt;/li&gt;
&lt;li&gt;on different Erlang nodes:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;without queuing mechanism: 1.6 million messages/min.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;with queuing mechanism: 960K messages/min.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4. &lt;strong&gt;Windows XP&lt;/strong&gt;, with 3.0GHz Intel Core 2 Duo E8400 and 2.5GB of DDR3 RAM memory.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on the same Erlang node: 24.7 million messages/min;&lt;/li&gt;
&lt;li&gt;on different Erlang nodes:
&lt;ul&gt;
&lt;li&gt;without queuing mechanism: 2.2 million messages/min.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;with queuing mechanism: 5.1 million messages/min.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As it is normal with Erlang, results are extremely different depending on many factor, one of which seems to be the OS. On the non-exhaustive tests here above, the qr mechanism does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;improve&lt;/strong&gt; message passing performance between Erlang nodes in the &lt;em&gt;OSX&lt;/em&gt; and &lt;em&gt;Windows&lt;/em&gt; environment;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;decrease&lt;/strong&gt; message passing performance between Erlang nodes in the &lt;em&gt;Ubuntu Linux&lt;/em&gt; environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I do not have the insights to understand which characteristics of each OS is switching results in this manner: TCP/IP flow, threads, I/O. Though, I&apos;m currently deploying a similar qr mechanism in my applications, which can be activated if necessary based on individual benchmarking tests.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;UPDATE [June 9th, 2009]&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I have had the availability of two HP ProLiant DL380, running Ubuntu 8.04 Server 32 bit, therefore I decided to take a shot also to test the same bench on different machines.&lt;/p&gt;
&lt;p&gt;Here is a summary of the results of these tests. As usual, please bear in mind that these results are definitely non exhaustive.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on the same Erlang node: 5.3 million messages/min [on both machines];&lt;/li&gt;
&lt;li&gt;on two different Erlang nodes, both running on the &lt;em&gt;same machine&lt;/em&gt;:
&lt;ul&gt;
&lt;li&gt;without queuing mechanism: 1.7 K million messages/min.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;with queuing mechanism: 3.1 million messages/min&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;on two different Erlang nodes, each running on a &lt;em&gt;different machine&lt;/em&gt;:
&lt;ul&gt;
&lt;li&gt;without queuing mechanism: 1.7 K million messages/min.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;with queuing mechanism: 3.2 million messages/min&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This seems to state that the qr mechanism does &lt;strong&gt;improve&lt;/strong&gt; message passing performance between Erlang nodes, also on the &lt;strong&gt;Ubuntu 8.04&lt;/strong&gt; environment.&lt;/p&gt;
&lt;p&gt;I&apos;ve also updated the original code, so that the destination node identifier is now extracted from the recipient Pid and thus it is not necessary to pass it as variable. This code can be found &lt;a href=&quot;/media/2009/06/erlang_mq_boost_2.zip&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>OpenSpime</title><link>https://www.ostinelli.net/openspime/</link><guid isPermaLink="true">https://www.ostinelli.net/openspime/</guid><description>OpenSpime is a protocol, an open XMPP custom extension enabling physical devices to communicate. It has been written with the Internet of Things in mind. A Technical Introduction to OpenSpime OpenSpime Buzz The whole buzz started when the following video was presented. One of the first persons to blog about this was Bruce Sterling in his blog on Wired,…</description><pubDate>Tue, 10 Jun 2008 18:04:13 GMT</pubDate><content:encoded>&lt;p&gt;OpenSpime is a protocol, an open &lt;a href=&quot;http://www.xmpp.org&quot;&gt;XMPP&lt;/a&gt; custom extension enabling physical devices to communicate. It has been written with the &lt;a href=&quot;http://en.wikipedia.org/wiki/Internet_of_Things&quot;&gt;Internet of Things&lt;/a&gt; in mind.&lt;/p&gt;
&lt;h3 id=&quot;a-technical-introduction-to-openspime&quot;&gt;A Technical Introduction to OpenSpime&lt;/h3&gt;
&lt;p&gt;&lt;object width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;https://www.youtube.com/v/j4Q_qpCrkIc&amp;amp;hl=en&amp;amp;fs=1&quot;&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;https://www.youtube.com/v/j4Q_qpCrkIc&amp;amp;hl=en&amp;amp;fs=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;allowfullscreen&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/object&gt;&lt;/p&gt;

&lt;h3 id=&quot;openspime-buzz&quot;&gt;OpenSpime Buzz&lt;/h3&gt;
&lt;p&gt;The whole buzz started when the following video was presented. One of the first persons to blog about this was Bruce Sterling in his blog on Wired, &lt;a href=&quot;http://blog.wired.com/sterling/2008/03/spime-watch-the.html&quot;&gt;Beyond the Beyond&lt;/a&gt;, but OpenSpime has had a worldwide coverage since then (&lt;a href=&quot;http://itc.conversationsnetwork.org/shows/detail3587.html&quot;&gt;IT Conversations&lt;/a&gt;, &lt;a href=&quot;http://blogs.cisco.com/virtualworlds/comments/designing_the_shape_of_space_time/&quot;&gt;Cisco&apos;s blogs&lt;/a&gt;, &lt;a href=&quot;http://www.lunchoverip.com/2008/03/openspimes-turn.html&quot;&gt;Lunch Over IP&lt;/a&gt;, and &lt;a href=&quot;http://www.ugotrade.com/2008/03/03/openspime-instrumentation-for-the-planet/%22&quot;&gt;Ugotrade&lt;/a&gt; amongst others).&lt;/p&gt;
&lt;p&gt;&lt;object width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;https://www.youtube.com/v/xmiG2MzPMnA&amp;amp;hl=en&amp;amp;fs=1&quot;&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;https://www.youtube.com/v/xmiG2MzPMnA&amp;amp;hl=en&amp;amp;fs=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;allowfullscreen&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/object&gt;&lt;/p&gt;
&lt;h3 id=&quot;openspime-developer-network&quot;&gt;OpenSpime Developer Network&lt;/h3&gt;
&lt;p&gt;Together with Davide &apos;Folletto&apos; Casali, I&apos;ve written a python library called &lt;a href=&quot;https://github.com/ostinelli/pyopenspime&quot;&gt;PyOpenSpime&lt;/a&gt; which will easily get you started to OpenSpime.&lt;/p&gt;
</content:encoded></item><item><title>The Composite Intelligence of Virtual Assistants</title><link>https://www.ostinelli.net/the-composite-intelligence-of-virtual-assistants/</link><guid isPermaLink="true">https://www.ostinelli.net/the-composite-intelligence-of-virtual-assistants/</guid><description>As early as 1968, influenced by visionary movies such as Stanley Kubrick’s 2001: A Space Odyssey, with its fictional computer character HAL 9000, we envisioned omniscient, intelligent machines that could easily contain the whole range of human knowledge. Then, in 1987, the Knowledge Navigator video from Apple Computer struck our imaginations and greatly…</description><pubDate>Wed, 10 Oct 2007 15:32:49 GMT</pubDate><content:encoded>&lt;p&gt;As early as 1968, influenced by visionary movies such as Stanley Kubrick’s &lt;em&gt;2001: A Space Odyssey&lt;/em&gt;, with its fictional computer character HAL 9000, we envisioned omniscient, intelligent machines that could easily contain the whole range of human knowledge. Then, in 1987, the &lt;a href=&quot;http://www.youtube.com/watch?v=HGYFEI6uLy0&quot;&gt;Knowledge Navigator video&lt;/a&gt; from Apple Computer struck our imaginations and greatly boosted our expectations of what computers would be able to do for us in a few years’ time.&lt;/p&gt;
&lt;p&gt;It is now 20 years later, but technology is still very far from fulfilling such hopes regarding virtual assistants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Voice recognition isn’t immediate.&lt;/li&gt;
&lt;li&gt;People adapt to machines’ lexicons rather than the other way around.&lt;/li&gt;
&lt;li&gt;Computers cannot easily transcend the scope for which they have been programmed.&lt;/li&gt;
&lt;li&gt;Self-learning machines are still experimental.&lt;/li&gt;
&lt;li&gt;The generation of high-quality graphics representing emotionally rich, 3-D avatars is far from being real time, cheap, or extensively available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The technology for fulfilling such high expectations simply does not yet exist. However, while we wait for technology to catch up with our dreams, the gap between our expectations and the reality of what we can now achieve has inspired two important trends in the development of virtual assistants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;simulation of generic conversations&lt;/li&gt;
&lt;li&gt;application-specific virtual assistants&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;from-the-generic-to-the-application-specific&quot;&gt;From the Generic to the Application Specific&lt;/h3&gt;
&lt;p&gt;Unfortunately, the first approach—a computer that can simulate a generic conversation with a real person—remains an unrealized dream. However, a series of intelligence-simulation experiments has culminated in the &lt;a href=&quot;http://www.loebner.net/Prizef/loebner-prize.html&quot;&gt;Loebner Prize in Artificial Intelligence&lt;/a&gt;—“the first formal instantiation of a Turing Test,” which demonstrates a computer’s intelligence and would award a gold medal and a $100,000 prize “for the first computer whose responses were indistinguishable from a human’s.” Every year, Hugh Loebner awards a bronze medal to the computer software that best simulates a generic conversation with a real person. Interestingly, Marvin Minsky, co-founder of MIT’s Artificial Intelligence (AI) Laboratory and author of several texts on AI, is one of the strongest critics of the Loebner Prize. He has even provocatively offered a &lt;a href=&quot;http://www.loebner.net/Prizef/minsky.html&quot;&gt;monetary reward&lt;/a&gt; to anyone who can successfully convince Loebner to revoke his prize.&lt;/p&gt;
&lt;p&gt;On the other hand, virtual assistant applications are moving toward becoming application specific, with the aim of responding appropriately to specific users’ needs by providing precise and relevant information.&lt;/p&gt;
&lt;p&gt;While the Turing Test approach might offer the fastest results in successfully simulating generic human conversations, in reality, these simulations are often nothing more than escamotages, or sleights of hand, and are not able to achieve a real understanding of users’ ideas. Such experiments concentrate on the use of various tricks to make users believe a virtual assistant has understood them, while in reality, it is more about&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;turning users’ questions back on them—as a psychiatrist would do, for instance&lt;/li&gt;
&lt;li&gt;suddenly changing the mood of the virtual assistant to surprise—covering the fact that it simply hadn’t understood the user’s input in the first place&lt;/li&gt;
&lt;li&gt;switching the topic of conversation to one the application can handle better—by pretending not to be interested in what a user has said&lt;/li&gt;
&lt;li&gt;building strong characters that tend to impose their will—thus getting control of the flow of a conversation to ensure it remains on safe ground&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the other hand, the second approach—application-specific virtual assistants—is a more slowly evolving process that would require considerable investment and the use of diverse software technologies. However, its aim is to try to build applications that actually can have a real understanding of users’ input. Circumscribing an application’s context simplifies the understanding of users’ needs, thus reducing the amount of intelligence it needs to understand and communicate effectively. This has the double effect of reducing technology requirements to a level we can realistically attempt and increasing the level of specialization each virtual assistant can achieve. We can concentrate all our efforts on an application’s main purpose rather than trying to support the broad knowledge that responding to generic conversations would require. Since, in comparison to the wide open context of the first approach, this approach limits an application’s context much more, it is generally less appealing to users’ imaginations, while at the same time, being much more effective in responding to users’ requests.&lt;/p&gt;
&lt;p&gt;While the tricks inherent in the first approach are definitely worth considering, with their goal of increasing the level of human-like interaction virtual assistant applications can offer, I believe only the second approach enables us to build applications that really meet users’ needs. Typically, users rather quickly become accustomed to a virtual assistant, but get annoyed by any useless chatter, so the ability to carry on a generic conversation might not be desirable anyway. Also, the goal of the second approach is to build business applications, so in my opinion, this will be the approach that leads us down the path toward intelligent virtual assistants.&lt;/p&gt;
&lt;h3 id=&quot;the-intelligence-of-software&quot;&gt;The Intelligence of Software&lt;/h3&gt;
&lt;p&gt;What we mean by &lt;em&gt;intelligent virtual assistants&lt;/em&gt; often points directly to our definition of &lt;em&gt;artificial intelligence&lt;/em&gt;. Each of us has some perception of what AI is, but if we try to unambiguously define it, we will rapidly fall into a series of borderless conceptions that bounce from science fiction reminiscences—the ability of the HAL 9000 to perceive the emotions of its interlocutors and understand &lt;em&gt;all&lt;/em&gt; of their requests—to pragmatic requirements—machines that can automate tasks requiring complex decisions—to cutting-edge technologies—self-learning machines—or to your impressions the first time you ever saw a computer providing an answer to a query of yours. So, as you can see, it is more a matter of people’s perception of what intelligence really is. When an AI application actually succeeds, it is common to hear comments like “It was not that hard after all,” or “It’s not real AI anyway.” According to AI pioneer Raymond Kurzweil, such responses are inherent in the nature of AI itself. As he said in a &lt;a href=&quot;http://news.com.com/2008-1082-254344.html&quot;&gt;c|net interview&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&quot;It turns out to be easy to replicate most adult achievements, like playing chess or guiding cruse missiles, etcetera. At least a lot of them we can replicate in machines. Every time a machine does that, it’s the nature of artificial intelligence to say, “Well, that wasn’t very difficult after all.” The hard things are what children do, recognizing parents or playing with a dog.&quot;&lt;/p&gt;
&lt;p&gt;You can easily imagine, therefore, why the definition of artificial intelligence has been cause for discussion for decades now.&lt;/p&gt;
&lt;p&gt;However, it is &lt;em&gt;not&lt;/em&gt; the purpose of this article to discuss &lt;em&gt;what&lt;/em&gt; artificial intelligence is or how we can emulate human intelligence. Rather, my intent is to understand &lt;em&gt;how&lt;/em&gt; virtual assistants can &lt;em&gt;approach&lt;/em&gt; intelligence—strictly from a pragmatic point of view.&lt;/p&gt;
&lt;p&gt;Since software is the primary factor in making a machine act intelligently, I prefer to use the term &lt;em&gt;software intelligence&lt;/em&gt; instead of &lt;em&gt;artificial intelligence&lt;/em&gt;. This avoids people’s being misled by the expectations surrounding the latter and allows us to concentrate on the practical considerations that are involved in the creation of intelligent virtual assistants.&lt;/p&gt;
&lt;p&gt;I have grouped the software intelligence we need to build virtual assistants into five different levels of intelligence, which together compose an intelligence users perceive as a monolithic, composite intelligence, within the context of their experience (thus, the use of the term &lt;em&gt;composite intelligence&lt;/em&gt; in this article’s title). The five levels of software intelligence are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;input intelligence&lt;/li&gt;
&lt;li&gt;emotional intelligence&lt;/li&gt;
&lt;li&gt;logical intelligence&lt;/li&gt;
&lt;li&gt;knowledge intelligence&lt;/li&gt;
&lt;li&gt;output intelligence&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Input Intelligence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are numerous input devices that enable a user to input his requests to a virtual assistant—for instance, keyboards, touch screens, microphones, even motion capture systems. Various types of &lt;em&gt;input intelligence&lt;/em&gt;—the first level of software intelligence—enable a virtual assistant to immediately interpret such inputs. Some examples include the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;s&lt;/strong&gt;emantic intelligence—A semantic engine can immediately parse the text a user enters via a keyboard and identify the user’s needs by disambiguating the semantic meaning of the user’s words, thus avoiding the misinterpretation of ambiguous requests.&lt;/li&gt;
&lt;li&gt;voice-recognition intelligence—Software can interpret the speed or change of tone in a user’s speech as emotional values that the other levels of intelligence can then use to more properly adapt to the user’s requests. Thus, voice recognition encompasses not only the ability to capture our words as we speak, but the intelligence enabling the software to perceive and interpret changes in speed and tone.&lt;/li&gt;
&lt;li&gt;facial-recognition intelligence—Software can also perceive a user smiling and interpret a smile as an emotional value that the other levels of intelligence can use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Input intelligence is, therefore, able to add a lot of metadata to the software’s understanding of a user’s intended inputs—the kinds of metadata that typically enhance human conversations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Emotional Intelligence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Input intelligence can understand both a user’s actual communications and the metadata relating to a user’s requests, which have intrinsic emotional value that emotional intelligence can interpret. For example, if a user angrily shook his arms while pronouncing the sentence “Yeah, you helped me alright,” emotional intelligence would correctly disambiguate the sentence. Rather than perceiving the remark to be of a positive and satisfied nature, which the user’s words alone would suggest, it would understand that, in reality, the user is unsatisfied with his experience.&lt;/p&gt;
&lt;p&gt;Moreover, by keeping track of a discussion’s evolution, software with emotional intelligence would gain a better understanding of the overall direction in which the dialogue was going—whether satisfying or dissatisfying to a user. Finally, emotional intelligence can also communicate a virtual assistant’s emotional status, which sets the ground for a more human-like type of interaction.&lt;/p&gt;
&lt;p&gt;Thus, &lt;em&gt;emotional intelligence&lt;/em&gt; can disambiguate mixed input signals, while providing an emotional dimension to the user experience by tracking the emotional status of both the user and the virtual assistant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Logical Intelligence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The software that provides logical intelligence evaluates &lt;em&gt;all&lt;/em&gt; available information and analyzes a user’s requests. It then continues the flow of the discussion by providing the virtual assistant’s next comment or question, or the answer to the user’s query, if it has already gathered all required information from the user.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Logical intelligence&lt;/em&gt; comprises the set of technologies that a virtual assistant uses to perform the necessary troubleshooting operations and manage the flow of discussion—such as rule-based engines, case-based reasoning, and bayesian or neural networks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Knowledge Intelligence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While logical intelligence performs the core tasks of troubleshooting and managing dialogue, it often needs to rely upon data to successfully perform such tasks. It is not enough to merely analyze a user’s needs and identify the related solution. It is of utmost importance that the data a virtual assistant gathers from its knowledge bases matches the information the logical intelligence requests.&lt;/p&gt;
&lt;p&gt;For example, if the logical intelligence has identified that a user wants to know about Polish furniture—that is, furniture manufactured in Poland—if the knowledge base were to reply with information on how to polish furniture—that is, clean it—it would have indeed failed to provide an intelligent response to the user’s query. In this case, the integration of a semantic search solution with the logical intelligence would have instead provided the correct information.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Knowledge intelligence&lt;/em&gt; lets a virtual assistant correctly gather data from knowledge bases. Not every interaction requires knowledge intelligence be consulted. For example, a single user input might be just a greeting, which logic intelligence alone could handle very well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output Intelligence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Output intelligence&lt;/em&gt; determines how a virtual assistant presents its response to a user’s request. It has at its disposal both the information the logical intelligence generated and that which the knowledge intelligence ultimately gathered. This information might be something the virtual assistant should say, but also might relate to documents or videos the user should view. Output intelligence also knows the emotional status of both the user and the virtual assistant.&lt;/p&gt;
&lt;p&gt;Therefore, output intelligence integrates &lt;em&gt;every&lt;/em&gt; bit of information and metadata that the other levels of software intelligence have computed, in order to build the best possible representation of the information. This includes graphic representations of facial expressions and gestures, voice patterns—which might reflect, for instance, the rush a user is in or the emotional status of the virtual assistant—and all of the interface design issues relating to the optimization of this representation.&lt;/p&gt;
&lt;h3 id=&quot;using-software-intelligence&quot;&gt;Using Software Intelligence&lt;/h3&gt;
&lt;p&gt;Attentive readers will already have figured out that these five levels of software intelligence occur sequentially. The progressive elaboration on a user’s input becomes enriched through the successive steps, until the software intelligence finds the data that matches the information the user has requested and presents it to the user. All &lt;em&gt;necessary&lt;/em&gt; levels of intelligence process every user request, to progressively identify what data the user is asking for. It is a process of &lt;em&gt;input targeting&lt;/em&gt;, which relates to identifying and disambiguating a user’s requests, while gradually performing a process of &lt;em&gt;output targeting&lt;/em&gt;, or computing the emotional and informational response that the software presents to satisfy a user’s request.&lt;/p&gt;
&lt;p&gt;These five levels of software intelligence can, in my opinion, make the dream of virtual assistants a reality. Collectively, they make up the concept of &lt;em&gt;composite intelligence&lt;/em&gt;, which comprises various software components—each gifted with some moderate degree of intelligence. Under the appropriate creative and technological conditions, this composite intelligence could provide a coherent solution that enables a degree of intelligence that might even be superior to the sum of its components. To fulfill the potential of such a solution, the individual components require a means of communication—including a common communications protocol—that can optimize and boost their overall performance.&lt;/p&gt;
&lt;p&gt;Hopefully, my attempt to classify the software components that together support the perceived intelligence of virtual assistants contributes to the development of an understanding of the diverse professional domains the realization of such applications touches. Most people can readily understand and accept that software that can compute and rationally respond to a user’s requests is a vital part of the composition of a virtual assistant. However, it rapidly becomes apparent that we can achieve this capability only by first deeply understanding the nature of a user’s needs by&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;using a combination of input technologies and emotional algorithms&lt;/li&gt;
&lt;li&gt;ensuring the appropriate integration of technology and data sources&lt;/li&gt;
&lt;li&gt;providing a rich user experience that gives users an overall feeling of confidence in virtual assistants&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ultimately, if we can achieve all of this, users will gain the necessary degree of familiarity with virtual assistants that will, in the end, open their minds to letting virtual assistants meet their needs.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a href=&quot;http://www.uxmatters.com/MT/archives/000224.php&quot;&gt;UXmatters&lt;/a&gt;, October 8th, 2007.&lt;/em&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>