Skip to content

"ReplyError: ERR unknown command evalsha, with args beginning with:" with redis sentinels #304

@AJackTi

Description

@AJackTi

My package's version:
redlock: 5.0.0-beta.2
ioredis: 5.4.1
redis server: 7.4.0
node: v22.6.0

My code:

const express = require("express");
const Redlock = require("redlock").default;
const { promisify } = require("util");
const Client = require("ioredis");
require("log-timestamp");

// Create and configure a webserver.
const app = express();
app.use(express.json());

const host = "192.168.1.211";
const redis1 = new Client({
  port: 26377,
  host,
});
const redis2 = new Client({
  port: 26378,
  host,
});
const redis3 = new Client({
  port: 26379,
  host,
});

const redlock = new Redlock([redis1, redis2, redis3], {
  driftFactor: 0.01,
  retryCount: 5,
  retryDelay: 200,
  retryJitter: 200,
});

redlock.on("clientError", function (err) {
  console.error("A redis error has occurred:", err);
});

// Adding a simple function to wait some time.
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Create and endpoint to lock a key value paire and set the value.
app.post("/lockAndSetValue", async (req, res) => {
  console.log("Request received!");
  if (req.body.key && req.body.value) {
    try {
      const resource = `lock:${req.body.key}:${Date.now()}`;
      console.log(`Resource: ${resource}`);
      const ttl = 2000;
      redlock.acquire([resource], ttl).then(async function (lock) {
        console.log("Lock acquired!");
        await redisSet(req.body.key, req.body.value);
        console.log(`SET key=${req.body.key} value=${req.body.value}`);
        console.log("Waiting some time...");
        await sleep(1000);
        console.log("Time finished, key unlocked!");
        return lock.unlock().catch(function (err) {
          console.error(err);
        });
      });

      // redlock.using([resource], ttl, async (signal) => {
      //   console.log(`Lock acquired for ${resource}`);
      //   try {
      //     console.log("Do something...");
      //   } catch (error) {
      //     console.error(error);
      //   } finally {
      //     console.log(`Lock released for ${resource}`);
      //   }
      // });

      console.log("Sending response!");
      res.send(resource);
    } catch (e) {
      res.json(e);
    }
  } else {
    res.status(400).json({ error: "Wrong input." });
  }
});

// Create an endpoint to set a key value pair.
app.post("/setValue", async (req, res) => {
  if (req.body.key && req.body.value) {
    try {
      await redisSet(req.body.key, req.body.value);
      console.log(`SET key=${req.body.key} value=${req.body.value}`);
      res.send();
    } catch (e) {
      res.json(e);
    }
  } else {
    res.status(400).json({ error: "Wrong input." });
  }
});

// Create an endpoint to get a key value pair.
app.get("/getValue/:key", async (req, res) => {
  if (!req.params.key) {
    return res.status(400).json({ error: "Wrong input." });
  }

  try {
    const value = await redisGet(req.params.key);
    console.log(`GET key=${req.params.key} value=${value}`);
    res.json(value);
  } catch (e) {
    res.json(e);
  }
});

// Start the webserver.
app.listen(3000, () => {
  console.log("Server is up on port 3000");
});

My docker-compose file to run redis sentinels:

services:
  redis-master:
    image: redis:6
    container_name: redis-master
    hostname: redis-master
    ports:
      - "6379:6379"
    volumes:
      - ./data/master:/data
    command:
      [
        "redis-server",
        "--appendonly",
        "yes",
        "--repl-diskless-load",
        "on-empty-db",
        "--replica-announce-ip",
        "${HOST_IP}",
        "--replica-announce-port",
        "6379",
        "--protected-mode",
        "no"
      ]
    networks:
      redis-net:
        ipv4_address: 172.21.0.3


  redis-slave-1:
    image: redis:6
    container_name: redis-slave-1
    hostname: redis-slave-1
    depends_on:
      - redis-master
    ports:
      - "6380:6379"
    volumes:
      - ./data/slave1:/data
    command:
      [
        "redis-server",
        "--appendonly",
        "yes",
        "--replicaof",
        "redis-master",
        "6379",
        "--repl-diskless-load",
        "on-empty-db",
        "--replica-announce-ip",
        "${HOST_IP}",
        "--replica-announce-port",
        "6380",
        "--protected-mode",
        "no"
      ]
    networks:
      redis-net:
        ipv4_address: 172.21.0.4


  redis-slave-2:
    image: redis:6
    container_name: redis-slave-2
    hostname: redis-slave-2
    depends_on:
      - redis-master
    ports:
      - "6381:6379"
    volumes:
      - ./data/slave2:/data
    command:
      [
        "redis-server",
        "--appendonly",
        "yes",
        "--replicaof",
        "redis-master",
        "6379",
        "--repl-diskless-load",
        "on-empty-db",
        "--replica-announce-ip",
        "${HOST_IP}",
        "--replica-announce-port",
        "6381",
        "--protected-mode",
        "no"
      ]
    networks:
      redis-net:
        ipv4_address: 172.21.0.5


  sentinel-1:
    image: redis:6
    container_name: sentinel-1
    hostname: sentinel-1
    depends_on:
      - redis-master
    ports:
      - "26379:26379"
    command: >
      sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf &&
            echo "sentinel monitor mymaster ${HOST_IP} 6379 2" >> /etc/sentinel.conf &&
            echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf &&
            echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf &&
            echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf &&
            echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf &&
            redis-sentinel /etc/sentinel.conf'
    networks:
      redis-net:
        ipv4_address: 172.21.0.6

  sentinel-2:
    image: redis:6
    container_name: sentinel-2
    hostname: sentinel-2
    depends_on:
      - redis-master
    ports:
      - "26378:26379"
    command: >
      sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf &&
            echo "sentinel monitor mymaster ${HOST_IP} 6379 2" >> /etc/sentinel.conf &&
            echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf &&
            echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf &&
            echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf &&
            echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf &&
            redis-sentinel /etc/sentinel.conf'
    networks:
      redis-net:
        ipv4_address: 172.21.0.7

  sentinel-3:
    image: redis:6
    container_name: sentinel-3
    hostname: sentinel-3
    depends_on:
      - redis-master
    ports:
      - "26377:26379"
    command: >
      sh -c 'echo "bind 0.0.0.0" > /etc/sentinel.conf &&
            echo "sentinel monitor mymaster ${HOST_IP} 6379 2" >> /etc/sentinel.conf &&
            echo "sentinel resolve-hostnames yes" >> /etc/sentinel.conf &&
            echo "sentinel down-after-milliseconds mymaster 10000" >> /etc/sentinel.conf &&
            echo "sentinel failover-timeout mymaster 10000" >> /etc/sentinel.conf &&
            echo "sentinel parallel-syncs mymaster 1" >> /etc/sentinel.conf &&
            redis-sentinel /etc/sentinel.conf'
    networks:
      redis-net:
        ipv4_address: 172.21.0.8

networks:
  redis-net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.21.0.0/16

When I run curl:

curl --location 'localhost:3000/lockAndSetValue' \
--header 'Content-Type: application/json' \
--data '{
    "key": "name",
    "value": "Roberto"
}'

I got the error message:

/Users/ajackti/Downloads/Code/Nodejs/node-redis-example-5/webservice-ver2/node_modules/redlock/dist/cjs/index.js:296
                throw new ExecutionError("The operation was unable to achieve a quorum during its retry window.", attempts);
                      ^

ExecutionError: The operation was unable to achieve a quorum during its retry window.
    at Redlock._execute (/Users/ajackti/Downloads/Code/Nodejs/node-redis-example-5/webservice-ver2/node_modules/redlock/dist/cjs/index.js:296:23)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Redlock.acquire (/Users/ajackti/Downloads/Code/Nodejs/node-redis-example-5/webservice-ver2/node_modules/redlock/dist/cjs/index.js:213:34) {
  attempts: [
    Promise {
      {
        membershipSize: 3,
        quorumSize: 2,
        votesFor: Set(0) {},
        votesAgainst: Map(3) {
          Commander {
            options: [Object],
            scriptsSet: {},
            addedBuiltinSet: Set(0) {},
            status: 'ready',
            isCluster: false,
            reconnectTimeout: null,
            connectionEpoch: 1,
            retryAttempts: 0,
            manuallyClosing: false,
            _autoPipelines: Map(0) {},
            _runningAutoPipelines: Set(0) {},
            _events: [Object: null prototype] {},
            _eventsCount: 0,
            _maxListeners: undefined,
            commandQueue: [Denque],
            offlineQueue: [Denque],
            connector: [StandaloneConnector],
            condition: [Object],
            stream: [Socket],
            [Symbol(shapeMode)]: false,
            [Symbol(kCapture)]: false
          } => ReplyError: ERR unknown command `evalsha`, with args beginning with: `96da70f7716f27d278a5218544df37fd8b0a5e4c`, `1`, `{resource}lock:name:1724811013590`, `beb20712d5d04dafa8e4b62f2b51a6fc`, `2000`, 
              at parseError (/Users/ajackti/Downloads/Code/Nodejs/node-redis-example-5/webservice-ver2/node_modules/redis-parser/lib/parser.js:179:12)
              at parseType (/Users/ajackti/Downloads/Code/Nodejs/node-redis-example-5/webservice-ver2/node_modules/redis-parser/lib/parser.js:302:14) {
            command: [Object]
          },
          Commander {
            options: [Object],
            scriptsSet: {},
            addedBuiltinSet: Set(0) {},
            status: 'ready',
            isCluster: false,
            reconnectTimeout: null,
            connectionEpoch: 1,
            retryAttempts: 0,
            manuallyClosing: false,
            _autoPipelines: Map(0) {},
            _runningAutoPipelines: Set(0) {},
            _events: [Object: null prototype] {},
            _eventsCount: 0,
            _maxListeners: undefined,
            commandQueue: [Denque],
            offlineQueue: [Denque],
            connector: [StandaloneConnector],
            condition: [Object],
            stream: [Socket],
            [Symbol(shapeMode)]: false,
            [Symbol(kCapture)]: false
          }

Please help me. I spent several days trying to address this, and my task’s deadline is approaching. I really need your help.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions