redis/node-redis

[Question] Order Guarantees with the Async API

Closed this issue · 4 comments

Hey,
I’m wondering if the following example guarantees execution order with node-redis async API:

await cluster.set('hello', 'cluster');
const value = await cluster.get('hello');

Does SET always execute before GET, even though SET wasn’t explicitly awaited?

Thanks!

Your code awaits the set though, so it will always execute before the get

oops, I meant:

cluster.set('hello', 'cluster');
const value = await cluster.get('hello');

Your latest example does not guarantee order. It effectively throws the promise into the event loop and since nothing resolves it, it has no dependencies and as such will resolve "whenever" it arrives.

To guarantee order, you must use await as you have originally posted or then such as

cluster.set('hello', 'cluster').then(res => cluster.get('hello')

I do want to add, that since the redis client library batches requests, my understanding is that practically speaking, those two promises will get batched into a single transaction and their order will be preserved. This isn't really explained anywhere in the docs and as such I would infer that there is no order guarantee unless it is specifically requested.

@LiraNuna Commands that are written on the same node tick are pipelined ( batched ) by default. This is why we don't have pipeline function anymore. see #2798

// this is going to be executed as a pipeline 
const replies = await Promise.all([
  client.get('a'),
  client.get('b')
]);

Also relevant about ordering

We empty ( write to socket ) as much as possible of the command queue at the end of each nodejs eventloop tick by using setImmediate ( see line in node-redis repo )

This schedules the "immediate" execution of the socket writes after I/O events' callbacks , which means that the client can auto pipeline ( without explicit grouping via Promise.all , etc ) the commands present in the queue.

When multiple calls to setImmediate() are made, the callback functions are queued for execution ** in the order in which they are created.**

The entire callback queue is processed every event loop iteration. If an immediate timer is queued from inside an executing callback, that timer will not be triggered until the next event loop iteration.