<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Munawwar</title>
    <description>The latest articles on DEV Community by Munawwar (@munawwar).</description>
    <link>https://dev.to/munawwar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F123234%2Ffdb9d1f7-6a12-4cb8-8ac1-9d4f4479ad65.jpeg</url>
      <title>DEV Community: Munawwar</title>
      <link>https://dev.to/munawwar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/munawwar"/>
    <language>en</language>
    <item>
      <title>Concurrent Redis writes and correctness (Take 2)</title>
      <dc:creator>Munawwar</dc:creator>
      <pubDate>Tue, 13 Jul 2021 10:01:27 +0000</pubDate>
      <link>https://dev.to/munawwar/concurrent-redis-writes-and-correctness-take-2-46h4</link>
      <guid>https://dev.to/munawwar/concurrent-redis-writes-and-correctness-take-2-46h4</guid>
      <description>&lt;p&gt;Last year I wrote a blog post on &lt;a href="https://dev.to/munawwar/concurrent-redis-writes-and-correctness-3fh3"&gt;concurrency control and ensuring data consistency&lt;/a&gt; while caching things to redis from multiple processes.&lt;/p&gt;

&lt;p&gt;Recently I revisited the blog post again and I couldn't help wonder &lt;em&gt;how over-complicated my final solution was&lt;/em&gt;. Custom lua script and stuff!?&lt;/p&gt;

&lt;p&gt;Here is my attempt to fix what I started. Going back to the initial requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Congestion Control - We need to try our best to call fetchFreshValues() as few times as possible, across all server processes, since it is expensive
(how expensive? e.g. it was a super slow end-point that internally fires 100 of MySQL queries, which if it runs too many times, will slow the database down to a halt).&lt;/li&gt;
&lt;li&gt;Data Consistency - We need to make sure that all processes returns a consistent value for a key. i.e. let's say our system calls fetchFreshValues() independently &amp;amp; parallelly from two processes, then only one should successfully write to redis whereas the other must fail.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last blog post I established that redlock (a distributed lock algorithm from folks at redis) is great at congestion control, even though there could be edge cases where two processes manage to get a lock.&lt;/p&gt;

&lt;p&gt;However for ensuring data consistency in the case two processes simultaneously gets hold of a lock, I did not have to go with a "versioned" solution. All I needed is redis to not overwrite a key if it already has a value. A simple &lt;code&gt;SET NX&lt;/code&gt; command would have done the trick.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; SET myKey "myValue" EX 60 NX
"OK"
&amp;gt; SET myKey "myValue" EX 60 NX
(nil)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a key expires, and if, two processes manage to get a lock, then only the first write would succeed. Which is what we wanted and is also how the old solution effectively worked. And with the return value, we can detect if a write succeeded or not.&lt;/p&gt;

&lt;p&gt;Love the simplicity of this solution over the previous one. That's all for this post. Thanks for reading.&lt;/p&gt;




&lt;p&gt;This post was reposted from &lt;a href="https://www.codepasta.com/distributed-systems/2021/07/13/concurrent-redis-writes-and-correctness-take-2.html" rel="noopener noreferrer"&gt;https://www.codepasta.com/distributed-systems/2021/07/13/concurrent-redis-writes-and-correctness-take-2.html&lt;/a&gt;. Follow my blog at &lt;a href="https://codepasta.com" rel="noopener noreferrer"&gt;codepasta.com&lt;/a&gt; for long-form articles.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Queues with Redis without duplicate items</title>
      <dc:creator>Munawwar</dc:creator>
      <pubDate>Mon, 28 Sep 2020 15:32:19 +0000</pubDate>
      <link>https://dev.to/munawwar/queues-with-redis-without-duplicate-items-4nlh</link>
      <guid>https://dev.to/munawwar/queues-with-redis-without-duplicate-items-4nlh</guid>
      <description>&lt;p&gt;I work on an ecommerce store (Shopify), that has got webhooks* to auto-fix product issues like wrong product details, auto-fix assignment to the wrong inventory location etc. The way the system worked previously was that any update to a product immediately does all the checks and computations to try and auto-fix that product's details.&lt;/p&gt;

&lt;p&gt;(* webhook is basically a trigger.. a notification. That is, I can set Shopify to notify me about all "product updates" or "order creation" etc to a URL on my server. The body of the http call is a JSON that I can process)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The way merchandisers update products are occasionally through bulk actions. That is, for example first they change multiple products' pricing and then the same products' inventory etc. And they do this in a space of couple of minutes. And this causes lots of hits to the same webhook. Note that many of the updates are to the same products, so they are "duplicates".&lt;/p&gt;

&lt;p&gt;Furthermore the webhook internally uses shopify APIs that are rate limited to around 2 requests per second. My webhooks were hitting this limit a lot especially when bulk actions are done. Which then requires retries, exponential backoff etc.&lt;/p&gt;

&lt;p&gt;Overall this means my system was doing a lot of duplicated work and was hitting some hard limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;The solution I imagined is that the webhook adds these product ids to a queue and every 30 minutes or so, take the ids from the queue, find unique ids and process them in one go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation 1 - RabbitMQ
&lt;/h2&gt;

&lt;p&gt;One of the often used queuing system is RabbitMQ. However RabbitMQ cannot de-duplicate the messages of the queue "nicely".&lt;/p&gt;

&lt;p&gt;What does "nicely" mean? Well.. there is a way, which involves reading all the messages in the queue, and then finding unique ones through code. That is, deduplication done by the consumer. I would rather not have duplicates in the queue in the first place, if possible.&lt;/p&gt;

&lt;p&gt;Besides I already have redis running. If redis can be used, I could avoid adding yet another system for me to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation 2 - Redis
&lt;/h2&gt;

&lt;p&gt;Redis has several data structures in its feature list. It has regular queues. But that is just like RabbitMQ in that messages will have to deduplicated by my code. Redis has got another interesting data structure called "sorted set".&lt;/p&gt;

&lt;p&gt;A sorted set is a data structure where each item in the set also has a numeric score, so that items can be fetched in sorted order of the scores.&lt;/p&gt;

&lt;p&gt;This data structure may not look very intuitive at first glance. A queue is a just a list.. pretty easy to understand. You can push and pop items to and from it. But how to use a sorted set as a queue?&lt;/p&gt;

&lt;p&gt;To build the intuition, note that even with queues each item in a queue have got a numeric association. If you are told that "you are the 10th person in the queue" means there are 9 people ahead of you. And the next person joining the queue will be the 11th person. If you think of position as a "score", then a queue's scoring logic for a new item is always the number of items previously in the queue + 1.&lt;/p&gt;

&lt;p&gt;But in a sorted set, the score for a new item doesn't have to be strictly the position of the item. It can be any increasing number.. like time. Time is easy to access as well. Though time can have duplicates if two items are added in the same millisecond. However in our case that is not a problem as sorted sets allows duplicate scores.. and few duplicate scores are ok, as long as they do not majorly alter the overall order of insertions. And we are more concerned about keys being unique.&lt;/p&gt;

&lt;p&gt;With that said, I am going to write down the redis command that will add a key to the sorted set if and only if it doesn't exist already in the set.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZADD product-updates NX &amp;lt;currentTimeInMilliseconds&amp;gt; product-id-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;NX&lt;/code&gt; in the command prevents duplicate product ids from getting into the "queue". Now from the consumer side, I can fetch all the oldest product ids that were added into the set and limit the result to 100. Note that I am not removing the items from the set.. just reading them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZRANGEBYSCORE product-updates 0 &amp;lt;currentTimeInMilliseconds&amp;gt; LIMIT 0 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can process each item (product id) and then remove the items either one by one as I process them, or remove all the 100 items in single command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZREM product-updates product-id-1 product-id-2 ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Workers and load-balancing
&lt;/h3&gt;

&lt;p&gt;For me a single process/thread is sufficient to do the job as I would hit shopify's rate limits if I try to parallelize the work. However, maybe for another use case that doesn't have such limits, you would probably like to have multiple workers doing the work. How would we do this?&lt;/p&gt;

&lt;p&gt;My solution would be with the following assumptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;we need to know how many workers are going to run upfront&lt;/li&gt;
&lt;li&gt;each worker will have a queue dedicated for itself&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The main problem here is ensuring de-duplication works now. How can we de-duplicate when there are multiple queues?&lt;/p&gt;

&lt;p&gt;The trick I am going to pull is by using a hash function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash("product-id") % numberOfQueues
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A hash function takes a string and returns a number. That's how the remainder operator &lt;code&gt;%&lt;/code&gt; can work. It will always return the same number for the same string. The hash function output must be pretty random for this to work reliably.&lt;/p&gt;

&lt;p&gt;There are several hash functions out there. One of my favorite is &lt;a href="[https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash"&gt;fnv1a&lt;/a&gt;, since it is tiny in implementation (literally 10 lines of code).&lt;/p&gt;

&lt;p&gt;So let's take an example. Let's say we have 4 workers/queues.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fnv1a("product-id-1") % 4 // = 0 always, if one uses https://www.npmjs.com/package/fnv1a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will always get the same queue number if you pass the the same product id. So producers don't need to handle duplicates, rather they try to consistently add a given product id to the same queue number as long as the number of queues is constant. And our ZADD NX command will handle duplicates within a queue.&lt;/p&gt;

&lt;p&gt;(By the way, this approach is also known as "sticky session load balancing")&lt;/p&gt;

&lt;p&gt;That's all for this post. The post was mostly about how to implement a queue with Redis without containing any duplicates.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Shorter Unique IDs</title>
      <dc:creator>Munawwar</dc:creator>
      <pubDate>Wed, 09 Sep 2020 13:38:45 +0000</pubDate>
      <link>https://dev.to/munawwar/shorter-unique-ids-4316</link>
      <guid>https://dev.to/munawwar/shorter-unique-ids-4316</guid>
      <description>&lt;h2&gt;
  
  
  Unique IDs
&lt;/h2&gt;

&lt;p&gt;If you have dealt with any form data &amp;amp; database, you have had the need to assign unique IDs to data saved. Many a time these IDs are internal, but sometimes  IDs need to be used in other ways by your users (e.g. to be emailed or pasted into some form etc). And the common two technique devs use for assigning an ID are either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a sequential number - an auto incrementing ID&lt;/li&gt;
&lt;li&gt;a random number generator - like UUID v4&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However they both have at least one downside. The downside of a sequential number is that (obviously) the IDs are too predictable. It is too easy to run some scraper iterating over your URLs.&lt;br&gt;
And the downside of uuid v4 is that, well, it's long and ugly.&lt;/p&gt;

&lt;p&gt;For internal IDs, that users don't need to deal with, both auto incrementing ID or uuid v4 seems fine. But when they got to paste it, email it or speak it over a phone or communicate it in any way, then it would be nicer to have shorter IDs. I have this use-case now, and I am thinking.. are any another alternatives where the IDs generated are shorter?&lt;/p&gt;


&lt;h2&gt;
  
  
  What does Stack overflow say?
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://stackoverflow.com/questions/18134627/how-much-of-a-git-sha-is-generally-considered-necessary-to-uniquely-identify-a/42567312#42567312" rel="noopener noreferrer"&gt;stack overflow answer&lt;/a&gt; gives me the math behind calculating the probability of generating a colliding ID. The math is called the "Birthday problem"&lt;/p&gt;

&lt;p&gt;Given &lt;code&gt;n&lt;/code&gt; number of IDs to generate and &lt;code&gt;c&lt;/code&gt; number of characters of &lt;code&gt;b&lt;/code&gt; character set (like hexadecimal), the probability of collision of IDs, approximately is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p (approximate) = (n^2) / (2 * b^c)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Academic note: the equation approximation assumes that p is less than 0.5)&lt;/p&gt;

&lt;p&gt;Cool! So let's decide on &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; and a "safe" probability of collision.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;n&lt;/code&gt; - the number of IDs we are going to generate. I am taking this number to be as 10 million. My data is not in the "big data" space so this is big enough.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b&lt;/code&gt; - character set. uuid v4 uses hex. But it's better if we can use a larger character set, since that would make the ID shorter. &lt;br&gt;
For my requirement, I need to be able to use it in a URL part (and also be printable on paper). So I am going for upper case alphanumeric characters. Which gives us 36 characters. I would take a tip from &lt;a href="https://en.bitcoin.it/wiki/Base58Check_encoding" rel="noopener noreferrer"&gt;Base58 encoding&lt;/a&gt; and avoid visually similar characters (namely 0,O,I and L), but.. for this post let me stick to upper case alphanumeric characters.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;p&lt;/code&gt; - and finally a "safe" margin for collisions. I have run simulation tests on various &lt;code&gt;p&lt;/code&gt; values, and figured out 0.001 is sufficient to ensure IDs are unique, given that you are using a reasonably good pseudo random number generator. I am using node.js &lt;code&gt;Math.random()&lt;/code&gt; function (Math.random() is "crackable"/predictable though, so if you want more security use a secure random number generator).&lt;/p&gt;

&lt;p&gt;We can now compute how many characters that is required:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0.001 = (10^7)^2 / (2 * 36^c)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And the &lt;a href="https://www.wolframalpha.com/input/?i=solve+for+real+number+c+in+0.001+%3D+%2810%5E7%29%5E2+%2F+%282*36%5Ec%29" rel="noopener noreferrer"&gt;answer is&lt;/a&gt; approximately 11 character length.&lt;/p&gt;

&lt;p&gt;So for 10m items, a 11 character alphanumeric ID seems sufficient to prevent ID collisions.&lt;/p&gt;


&lt;h2&gt;
  
  
  Sortability
&lt;/h2&gt;

&lt;p&gt;The random IDs I have suggested so far are not sortable by creation date. Being able to sort the IDs, also makes sequential access (from disk) for databases faster. So some databases &lt;a href="https://docs.mongodb.com/manual/reference/method/ObjectId/" rel="noopener noreferrer"&gt;like MongoDB&lt;/a&gt; use a timestamp prefix and random suffix to generate their IDs. This would keep the ID pretty random looking, and yet sortable by string prefix.&lt;/p&gt;

&lt;p&gt;One such convention would be = "YYSSSSSRRRR"&lt;br&gt;
where&lt;br&gt;
YY = year in base 36, "zero" padded to 2 character length&lt;br&gt;
SSSSS = seconds from start of year in base 36, "zero" padded to 5 character length,&lt;br&gt;
RRRR = 4 random base 36 characters,&lt;br&gt;
giving total of 11 character length like the math I calculated before&lt;/p&gt;

&lt;p&gt;Additional reference on this topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://eager.io/blog/how-long-does-an-id-need-to-be/" rel="noopener noreferrer"&gt;eager.io/blog/how-long-does-an-id-need-to-be/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/" rel="noopener noreferrer"&gt;percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's all folks. You can use the math and adjust the character length for your use case. The point of this post was to come up with an educated guess on how many characters you really need.&lt;/p&gt;


&lt;h3&gt;
  
  
  Implementation with JS
&lt;/h3&gt;

&lt;p&gt;If I go for the 32 glyph character set, the character length I need is still 11 characters. So I am going to implement that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;characterSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123456789ABCDEFGHJKMNPQRSTUVWXYZ&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateUniqueId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/x/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;characterSet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;generateUniqueId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// e.g. YMSATXVFM94AG&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  Blog Post Revision 2021
&lt;/h4&gt;

&lt;p&gt;In the initial version of this blog post:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I used &lt;code&gt;p&lt;/code&gt; value in percentage. Thats the way I was thinking at that point in time. But in mathematic literature, everyone use &lt;code&gt;p&lt;/code&gt; as a value between 0 and 1. Also saying "0.1%" is no more intuitive than saying "0.001", so I changed equation back to value between 0 and 1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I tried to make the IDs "unguessable" to brute force attacks over an HTTP end-point.  I took a arbitrary number to multiply the &lt;code&gt;p&lt;/code&gt; value with, to try and protect from such attacks, but in reality a brute force attack's success totally depends on how many requests the attacker can make to the end-point. I don't want to get deeper into that topic for now. So the value of &lt;code&gt;p&lt;/code&gt; is now based on &lt;code&gt;n&lt;/code&gt;, the max number of IDs that one intended to generate, which I used in my collision simulation tests as well.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;



</description>
      <category>database</category>
    </item>
    <item>
      <title>Lodash chaining alternative</title>
      <dc:creator>Munawwar</dc:creator>
      <pubDate>Wed, 15 Jul 2020 21:04:33 +0000</pubDate>
      <link>https://dev.to/munawwar/lodash-chaining-revisited-1c5d</link>
      <guid>https://dev.to/munawwar/lodash-chaining-revisited-1c5d</guid>
      <description>&lt;p&gt;Those of you dealing with data transforms/manipulations for charting/dashboards/whatever, need no introduction to Lodash library, and have been using it happily on the backend, frontend etc&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;However there is one method Lodash has that's so useful but has its performance implications on the frontend.. namely &lt;code&gt;chain()&lt;/code&gt;.&lt;br&gt;
On the frontend if you naively import &lt;code&gt;chain&lt;/code&gt; the entire lodash library will end up in your bundle.. and the entire lodash library isn't small. Backend code doesn't care about some extra bloat.&lt;/p&gt;

&lt;p&gt;That's sad. &lt;code&gt;chain&lt;/code&gt; is very useful and I would like to use chaining on the frontend without having to take a performance hit. So.. what is the solution?&lt;/p&gt;
&lt;h2&gt;
  
  
  What does Google say?
&lt;/h2&gt;

&lt;p&gt;Googling around you would see many suggestions to use lodash/fp's &lt;code&gt;flow()&lt;/code&gt; method. You can see the code from &lt;a href="https://medium.com/bootstart/why-using-chain-is-a-mistake-9bc1f80d51ba" rel="noopener noreferrer"&gt;this 2016 post&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash/fp/map&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;flatten&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash/fp/flatten&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sortBy&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash/fp/sortBy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;flow&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash/fp/flow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="nx"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;)([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works.. it keeps the bundle size small and gives you chaining capability.&lt;/p&gt;

&lt;p&gt;But there is something bothersome about that code...&lt;/p&gt;

&lt;p&gt;&lt;code&gt;_.chain&lt;/code&gt; begins with the data you need to manipulate and then you call the transforms.. whereas &lt;code&gt;flow()&lt;/code&gt; begins with the transforms and ends with the data you want to manipulate. This isn't natural to read. It needs to be flipped around.&lt;/p&gt;

&lt;p&gt;[From &lt;code&gt;flow()&lt;/code&gt;'s perspective it is built as intended. flow is potentially built for reuse. Fine. However we still miss a closer alternative to &lt;code&gt;chain&lt;/code&gt;.]&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative solution
&lt;/h2&gt;

&lt;p&gt;My ideal syntax would be the following (for the same code sample from above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However most linter configurations would complain about the indented parentheses. So we need a dummy function and a &lt;code&gt;.value()&lt;/code&gt; to break out of the chain (like lodash already does)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Overall if you squint your eyes and ignore the &lt;code&gt;.fn()&lt;/code&gt;s, then it looks very similar to lodash's &lt;code&gt;_.chain&lt;/code&gt; syntax. And there is a way to implement this. I'll dive straight into the implementation which is small and probably don't need too much explanation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implementation brings some new opportunity considering how generic the approach is. &lt;/p&gt;

&lt;p&gt;The function doesn't know anything about lodash. It takes in any function. So you can write custom functions or use Math.* or Object.* functions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// result = 4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Improvement
&lt;/h2&gt;

&lt;p&gt;With a slight modification, we can make it call any function on result objects.&lt;/p&gt;

&lt;p&gt;Which mean for arrays, we can use native array map, filter etc, and we don't really need to use lodash's functions there. We should be able to do something like the following (using same example from before):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="c1"&gt;// ... blah&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of passing the function here we put a name of the method to be invoked from the intermediate result object/array. The implementation of &lt;code&gt;fn&lt;/code&gt; will change to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;](...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can further improve this to handle promises / async functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;](...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;](...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then it can be used as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
  &lt;span class="c1"&gt;// with method name&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="c1"&gt;// with functions&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I believe this is an improvement to the popular approaches suggested out there on the interwebz. Check it out, try it out.. criticism welcome.&lt;/p&gt;

&lt;p&gt;That's all folks. Hope you liked my short, hastily written post.&lt;/p&gt;

&lt;p&gt;Full code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @type {import('./chain').default} */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;](...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;](...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;chain.d.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ParametersExceptFirst&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;F&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MethodsOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;((...&lt;/span&gt;&lt;span class="na"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;V&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Awaited&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ParametersExceptFirst&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;MethodsOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Awaited&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Awaited&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;((...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MethodsOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Awaited&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;V&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EDIT 2022: Added type definition and improved implementation&lt;br&gt;
EDIT 2024: Added promise / async function handling&lt;/p&gt;

</description>
      <category>lodash</category>
      <category>javascript</category>
      <category>functional</category>
    </item>
    <item>
      <title>Concurrent Redis writes and correctness</title>
      <dc:creator>Munawwar</dc:creator>
      <pubDate>Sat, 22 Feb 2020 19:44:41 +0000</pubDate>
      <link>https://dev.to/munawwar/concurrent-redis-writes-and-correctness-3fh3</link>
      <guid>https://dev.to/munawwar/concurrent-redis-writes-and-correctness-3fh3</guid>
      <description>&lt;p&gt;Lately I've been trying to re-implement a cache library using redis. The  (simplified) requirement is to use cached value for a given key if present else fetch fresh value and cache the value to redis (on the first time or the first time after cache value expires). Also assume that fetching fresh value, even once, is a super expensive operation (it causes heavy load on the database).&lt;/p&gt;

&lt;p&gt;Seems like a simple requirement, right? But one does not simply write distributed system code!&lt;/p&gt;

&lt;p&gt;So we have couple of challenges here.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Congestion Control&lt;/em&gt; -  We need to try our best to call fetchFreshValues() as few times as possible, across all server processes, since it is expensive.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Data Consistency&lt;/em&gt; - We need to make sure that all processes returns a consistent value for a key. i.e. let's say our system calls fetchFreshValues() independently &amp;amp; parallelly from two processes, then only one should successfully write to redis whereas the other must fail.&lt;/p&gt;

&lt;p&gt;The one that failed must fetch whatever was saved and return that instead of the result of fetchFreshValues() it got. You might be asking whether this is necessary. I'd reckon that a system either fails or return a stale value rather than returning potentially different value than the other processes (i.e. correctness. though stale value blows away the "correctness" part of my blog's title I think.. but you can adapt the info from this blog for correctness by returning error in this case).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One way to achieve the above is to acquire a distributed lock on a key, then fetch latest value and write to redis. The recommendation from Redis is to use redlock for achieving distributed lock.&lt;br&gt;
And so for a long time we did use redlock for this, yet there has been criticism about the algorithm much before we started using it -&amp;gt; &lt;a href="https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html" rel="noopener noreferrer"&gt;https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main takeaway from Martin Kleppmann's post is that redlock's dependence on time cannot guarantee correctness on acquiring an exclusive lock nor for the subsequent database/storage operations. There may be situations that two process manages to acquire a lock to the same resource (either due to a system time reset or more likely because of the lock expiring before the DB/storage write began).&lt;/p&gt;

&lt;p&gt;Martin further suggests that to fix this, redlock needs to issue incrementing "fencing tokens", and that the storage layer collaborates to accept writes for only those tokens that are greater in number than the saved data's token number (conversely, reject writes that are lesser than or equal to the saved data's token number).&lt;/p&gt;

&lt;p&gt;However in my case, I am using Redis for the cache storage. And redis doesn't seem to have this kind of concurrency control out-of-the-box. If two parallel processes tries to write to the same key at the same time, redis will accept both and the last write wins.&lt;/p&gt;
&lt;h3&gt;
  
  
  The work-around
&lt;/h3&gt;

&lt;p&gt;UPDATE 2021: Read my new post on a &lt;a href="https://dev.to/munawwar/concurrent-redis-writes-and-correctness-take-2-46h4"&gt;simpler solution&lt;/a&gt;. You can skip to the last section of this post.&lt;/p&gt;
&lt;h3&gt;
  
  
  Old solution
&lt;/h3&gt;

&lt;p&gt;The first time I read the fencing tokens solution, it felt strongly similar to multi-version document systems (like CouchDB)... that rejects writes if the version sent doesn't match the one on disk (and the new version gets incremented on save). I think this is called multi-version concurrency control (MVCC).&lt;/p&gt;

&lt;p&gt;Redis can't do that out-of-the-box. But searching around, I came across a potential way to implement this. Using Redis scripts - which are custom Lua scripts that redis would run atomically and transactionally + gets rolled back if script fails part-ways. References -&amp;gt; &lt;a href="https://redis.io/topics/transactions" rel="noopener noreferrer"&gt;https://redis.io/topics/transactions&lt;/a&gt; and &lt;a href="https://redis.io/commands/eval" rel="noopener noreferrer"&gt;https://redis.io/commands/eval&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quoting the relevant sections:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Redis script is transactional by definition&lt;/p&gt;

&lt;p&gt;Also Redis guarantees that a script is executed in an atomic way: no other script or Redis command will be executed while a script is being executed. This semantic is similar to the one of MULTI / EXEC. From the point of view of all the other clients the effects of a script are either still not visible or already completed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seems cool. But what does redis do in a multi-node setup? From their docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All Redis commands must be analyzed before execution to determine which keys the command will operate on. In order for this to be true for EVAL, keys must be passed explicitly. This is useful in many ways, but especially to make sure Redis Cluster can forward your request to the appropriate cluster node.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok. So I presume, a multi-node setup means that a given key only has one master - i.e. keys are sharded across nodes. And that the non-master nodes are replicas. So redis uses the key passed as separate argument, to make the decision about which node the script would run on. Seems cool so far.&lt;/p&gt;

&lt;p&gt;Yet another question remains. What about replicas? We know replicas are async in nature, but will the script execute &lt;em&gt;in order&lt;/em&gt; on the replicas as the original order? I don't know the answer to this. I am guessing "yes".&lt;/p&gt;

&lt;p&gt;Assuming the answer is "yes, order is maintained on replicas", then that does make redis scripts an option to implement a simple version check before every write.&lt;/p&gt;

&lt;p&gt;So let's dive in to my potential solution (Lua codez!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;newPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;newVersionStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"^([0-9]+)|(.+)$"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;prevVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;KEYS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prevVal&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'set'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;KEYS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s2"&gt;"1|"&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;oldVersionStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oldData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prevVal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"^([0-9]+)|(.+)$"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;newVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tonumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newVersionStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;oldVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tonumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldVersionStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- check if version matches before writing&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;oldVersion&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newVersion&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'set'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;KEYS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;newPayload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redis command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EVAL "the script as above" 1 "key-to-write" "new-version-number|new data"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I am doing there is writing a version number for the first write and making sure that for subsequent writes, the application sends the data along with plus-oned version number. If two processes try to use the same version, then the first one would succeed and second would receive &lt;code&gt;null&lt;/code&gt;. The one that received &lt;code&gt;null&lt;/code&gt; would then know that another process has changed the data, so it can handle the case appropriately.&lt;/p&gt;

&lt;p&gt;Two small notes here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I didn't use JSON for saving version number, cause some of our JSONs are so huge that it did slow down node.js's JSON.parse() in the past (but this may not be true for redis/lua, I didn't measure it).&lt;/li&gt;
&lt;li&gt;The version check is pretty rigid &lt;code&gt;oldVersion == (newVersion - 1)&lt;/code&gt;. Probably making the check as &lt;code&gt;newVersion &amp;gt; oldVersion&lt;/code&gt; would suffice and potentially make the writes order insensitive for the replicas.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I think that prevents unintentional overwrites of data by two parallel processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notes
&lt;/h3&gt;

&lt;p&gt;At this point you might ask, whether there is a point in using redlock anymore? I think it is still valuable... as even though it does not solve for data consistency, it still solves congestion control (from my initial requirements). From a probabilistic perspective, the system most likely would only have one write-lock per resource and the lock acquirer successfully writes to storage before the lock expires. This would work &lt;em&gt;most of the time&lt;/em&gt;. And the "most of the time" is what's important for congestion control. So I would implement the data consistency solution, plus also keep redlock.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed this piece. I'd like more eyes reviewing that code I wrote there.  &lt;a href="https://gist.github.com/Munawwar/78db6bae5212afef48380c978bd27e47" rel="noopener noreferrer"&gt;Here is the code with a small test to play with&lt;/a&gt;. Any criticism welcome.&lt;/p&gt;




&lt;p&gt;This post was reposted from &lt;a href="https://www.codepasta.com/distributed-systems/2020/02/22/concurrent-redis-writes-and-correctness.html" rel="noopener noreferrer"&gt;https://www.codepasta.com/distributed-systems/2020/02/22/concurrent-redis-writes-and-correctness.html&lt;/a&gt;. Follow &lt;a href="https://twitter.com/munawwarfiroz" rel="noopener noreferrer"&gt;me on twitter&lt;/a&gt; for short ideas/tips/tricks on programming and follow my blog at &lt;a href="http://www.codepasta.com" rel="noopener noreferrer"&gt;codepasta.com&lt;/a&gt; for long-form articles.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>distributedsystems</category>
      <category>concurrency</category>
    </item>
  </channel>
</rss>
