redis / node-redis

Redis Node.js client
https://redis.js.org/
MIT License
16.85k stars 1.87k forks source link

Has the pipeline function been removed from node-redis? #2798

Closed itsvinayak closed 1 month ago

itsvinayak commented 1 month ago

Description

Hi,

I remember using the pipeline function in node-redis to batch commands and execute them together. Is this function now deprecated? Has it been replaced with automatic pipelining within the client?

Here's an example of how I've been using the pipeline function:

const redis = require("redis");
const client = redis.createClient();

client.on("error", (err) => {
  console.error("Error:", err);
});

function usePipelining() {
  // Create a pipeline within the client
  const pipeline = client.pipeline();

  pipeline.set("key1", "value1");
  pipeline.set("key2", "value2");
  pipeline.set("key3", "value3");
  pipeline.get("key1");
  pipeline.get("key2");
  pipeline.get("key3");

  // Execute the pipeline and handle results
  pipeline.exec((err, results) => {
    if (err) {
      if (err instanceof redis.RedisError) {
        console.error("Redis Error:", err);
      } else {
        console.error("Pipeline Execution Error:", err);
      }
      return;
    }

    console.log("Pipeline results:");
    results.forEach((result, index) => {
      if (result === null) {
        console.log(`Key ${index + 1} doesn't exist`);
      } else {
        console.log(result);
      }
    });
    client.quit();
  });
}

usePipelining();

Can someone clarify if the pipeline function is still the recommended way to batch commands, or should we rely on automatic pipelining features in newer versions of node-redis?

Environment Details:

Node.js version: v22.2.0 node-redis version: v4.6.15 Redis Server Version: v7.0.15 Operating System: Ubuntu 24.04

itsvinayak commented 1 month ago

@sjpotter

leibale commented 1 month ago

commands that are written on the same "tick" are auto pipelined, so you can just:

const replies = await Promise.all([
  client.get('a'),
  client.get('b')
]);

you can also execute a multi as a pipeline (without the "MULTI" and "EXEC" wrappers):

const replies = await client.multi()
  .get('a')
  .get('b')
  .execAsPipeline();
itsvinayak commented 1 month ago

Hi @leibale

Has client.pipeline() or client.batch() been deprecated?

itsvinayak commented 1 month ago

For documentation purposes

execAsPipeline:

@leibale please correct me if I'm wrong.

itsvinayak commented 1 month ago

https://itsvinayak.hashnode.dev/redis-pipelining-in-nodejs

leibale commented 1 month ago

@itsvinayak sorry for the late reply, but: "Similar to exec, this command executes the queued commands as a pipeline instead of a transaction." - correct. "Non-atomicity: execAsPipeline doesn't guarantee atomicity. It sends commands to the server in a single network round trip but doesn't ensure that the operations are executed as a single atomic block." - not 100% correct, "It sends commands to the server in a single network round trip" - it'll be executed in "one round trip" as long as the socket "can handle it" (it will follow the "drain" events). "Performance: It can be faster for bulk operations since it reduces the number of network round trips but lacks atomic guarantees." - with auto pipelining on the performance of these 2 should be similar:

await client.multi()
  .get('a')
  .get('b')
  .execAsPipeline();

await Promise.all([
  client.get('a'),
  client.get('b')
]);

TBH, the only reason to use "pipeline" is:

  1. when sometimes you execute it as a multi
    
    const mutli = client.multi()
    .ping();

if (Math.random() > 0.5) { await multi .set('a', 'b') .exec(); } else { await multi.execAsPipeline(); }

2. when you are reusing the same "pipeline" multiple times
```javascript
const incrPipeline = client.multi()
  .incr('a')
  .incr('b');

await Promise.all([
  incrPipeline.execAsPipeline(),
  incrPipeline.execAsPipeline()
]);
itsvinayak commented 1 month ago

Thank you for providing clarification, @leibale