Blocking retrieval #EC3: Client receiving unexpected response

I’m stuck on Stage Blocking retrieval #EC3.

I have implemented BLPOP command with proxies and promises. but I keep getting an error that client 1 ( first subscriber of blpop ) received a different response. Maybe I didn’t understand the behavior of this command well enough. Please ignore the context from “your program” logs below if its confusing.

Here are my logs:

[compile] Moved ./.codecrafters/run.sh → ./your_program.sh
[compile] Compilation successful.
[tester::#EC3] Running tests for Stage #EC3 (Lists - Blocking retrieval)
[tester::#EC3] $ ./your_program.sh
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.267Z","context":{},"msg":"Logs from your program will appear here!"}
[tester::#EC3] [client-1] $ redis-cli BLPOP blueberry 0
[tester::#EC3] [client-2] $ redis-cli BLPOP blueberry 0
[tester::#EC3] [client-3] $ redis-cli RPUSH blueberry raspberry
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.324Z","context":{"traceId":"9f149790-2ad4-4517-a1bd-1f62bd7ccf02"},"msg":"BLPOP"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.324Z","context":{"traceId":"afc85221-5dff-476f-8127-dbcb7a65ffd5"},"msg":"BLPOP"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"b94e6091-adf1-4e26-9854-fe6229483cf3"},"msg":"RPUSH"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"b94e6091-adf1-4e26-9854-fe6229483cf3"},"msg":"Time Taken for execution - 1"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"b94e6091-adf1-4e26-9854-fe6229483cf3"},"msg":"calling mutation observers - 2"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"b94e6091-adf1-4e26-9854-fe6229483cf3"},"msg":"triggering callback"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"b94e6091-adf1-4e26-9854-fe6229483cf3"},"msg":"triggering callback"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"9f149790-2ad4-4517-a1bd-1f62bd7ccf02"},"msg":"result - blueberry,raspberry"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"afc85221-5dff-476f-8127-dbcb7a65ffd5"},"msg":"result - blueberry,raspberry"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"9f149790-2ad4-4517-a1bd-1f62bd7ccf02"},"msg":"Time Taken for execution - 1"}
[your_program] {"level":"INFO","time":"2026-04-29T08:14:37.325Z","context":{"traceId":"afc85221-5dff-476f-8127-dbcb7a65ffd5"},"msg":"Time Taken for execution - 1"}
[tester::#EC3] [client-3] ✔︎ Received 1
[tester::#EC3] Expecting 1 client to receive response of BLPOP command
[tester::#EC3] [client-2] ✔︎ Received ["blueberry", "raspberry"]
[tester::#EC3] [client-1] Expecting no response
[tester::#EC3] client-1 received unexpected response: "*2\r\n$9\r\nblueberry\r\n$9\r\nraspberry\r\n"
[tester::#EC3] Test failed

And here’s a snippet of my code:

const { logger } = require("../contextualLogger");
const { redisLookup } = require("../inMemoryLookup/index");
const {
  encodeToRespBulkString,
  encodeToRespArray,
} = require("../respParser/index");

const observersLookup = new Map();

function createObservableArray() {
  let timeout;
  let isManualMutation = false;

  const observed = new Proxy([], {
    set(target, prop, value) {
      target[prop] = value;
      if (!isManualMutation && observersLookup.get(observed)) {
        // Clear and reset a timer so the logic runs only ONCE after the last set
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          isManualMutation = true;
          const removedValue = observed.shift();
          const callbacks = observersLookup.get(observed);
          logger.info(`calling mutation observers - ${callbacks.length}`);
          callbacks.forEach((cb) => cb(removedValue));
          observersLookup.delete(observed);
          isManualMutation = false;
        }, 0);
      }

      return true;
    },
  });

  return observed;
}

async function blPopCommand(listName, timer = 0) {
  timer = +timer;
  let list = redisLookup[listName];

  if (!list) {
    list = createObservableArray();
    redisLookup[listName] = list;
  }

  let result;

  if (!list[0]) {
    let observersList = observersLookup.get(list);
    if (!observersList) {
      observersList = [];
      observersLookup.set(list, observersList);
    }
    result = await new Promise((res, rej) => {
      const callback = (removedValue) => {
        logger.info("triggering callback");
        res([listName, removedValue]);
      };
      observersList.push(callback);
      if (timer) {
        logger.info(`setting timer - ${timer}`);
        setTimeout(() => {
          observersLookup.set(
            list,
            observersList.filter((cb) => cb !== callback),
          );
          res([]);
        }, timer * 1000);
      }
    });
    logger.info(`result - ${result}`);
  } else {
    const removedValue = list.shift();
    result = [listName, removedValue];
  }

  const res = encodeToRespArray(result.map(encodeToRespBulkString));
  return res;
}

module.exports = {
  blPopCommand,
};

I am attaching my github repo link with main.js files as well
CC Redis - main.js

Hey @VIGNESHWAR-RV, could you check if you’ve ensured that only one blocked client can receive the popped element, when multiple clients are blocked on the same list?

Let me know if you need help debugging this further.

ohh. I didn’t ensure only one client should receive the popped element. I thought the popped element should be notified to all the clients ( starting with longest waiting client a.k.a first blocked client ( client 1 )).
is it like only the first blocked client should be responded and not any others ?.
Incase of multiple elements added to the list, should the behavior remain same with only one client ? or should we notify all the blocking clients with subsequent popped elements from the list ?.

I just completed the challenge by restricting the response to only the longest waiting client. but it would be really really helpful to if you could share details on the following.

  1. please elaborate the behavior of this blpop command ( especially when there are multiple clients and there are multiple elements added to the list )

  2. your insights on the folder structure and the implementation approach I have taken. I understand this ticket is not for code review but it really gives me a clarity on moving forward.

Here’s the core idea of BLPOP: it behaves like a queue of waiting clients.

  • Each pushed element is delivered to exactly one client
  • Clients are served in FIFO order (longest waiting first)
  • If multiple elements arrive, they’re distributed one-by-one to waiting clients

I’m not a JavaScript expert, so I may not be the best person to comment on the structure or implementation. I’ll leave this open for others in the community who can provide more detailed feedback.

thanks a lot for the explanation. it gives me clear idea on how BLPOP should be implemented.