[Gleam] Stuck on Redis Challenge, Replication, Stage 13

I’m stuck on Stage #YG4.

The whole of the handshake process works fine, and the Master apparently does propagate commands to the Replicas, seeing as I passed the previous Stage.

Here are my logs:

[compile] Compilation successful.

Debug = true

[tester::#YG4] Running tests for Stage #YG4 (Replication - Command Processing)
[tester::#YG4] Master is running on port 6379
[tester::#YG4] $ ./spawn_redis_server.sh --port 6380 --replicaof "localhost 6379"
[your_program]    Compiled in 0.02s
[your_program]     Running redis.main
[tester::#YG4] master: Waiting for replica to initiate handshake with "PING" command
[tester::#YG4] master: Received bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#YG4] master: Received RESP array: ["PING"]
[tester::#YG4] Received ["PING"]
[tester::#YG4] master: Sent "PONG"
[tester::#YG4] master: Sent bytes: "+PONG\r\n"
[tester::#YG4] master: Waiting for replica to send "REPLCONF listening-port 6380" command
[tester::#YG4] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n"
[tester::#YG4] master: Received RESP array: ["REPLCONF", "listening-port", "6380"]
[tester::#YG4] Received ["REPLCONF", "listening-port", "6380"]
[tester::#YG4] master: Sent "OK"
[tester::#YG4] master: Sent bytes: "+OK\r\n"
[tester::#YG4] master: Waiting for replica to send "REPLCONF capa" command
[tester::#YG4] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n"
[tester::#YG4] master: Received RESP array: ["REPLCONF", "capa", "psync2"]
[tester::#YG4] Received ["REPLCONF", "capa", "psync2"]
[tester::#YG4] master: Sent "OK"
[tester::#YG4] master: Sent bytes: "+OK\r\n"
[tester::#YG4] master: Waiting for replica to send "PSYNC" command
[tester::#YG4] master: Received bytes: "*3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n"
[tester::#YG4] master: Received RESP array: ["PSYNC", "?", "-1"]
[tester::#YG4] Received ["PSYNC", "?", "-1"]
[tester::#YG4] master: Sent "FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0"
[tester::#YG4] master: Sent bytes: "+FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0\r\n"
[tester::#YG4] Sending RDB file...
[tester::#YG4] master: Sent bytes: "$88\r\nREDIS0011\xfa\tredis-ver\x057.2.0\xfa\nredis-bits\xc0@\xfa\x05ctime\xc2m\b\xbce\xfa\bused-mem°\xc4\x10\x00\xfa\baof-base\xc0\x00\xff\xf0n;\xfe\xc0\xffZ\xa2"
[tester::#YG4] Sent RDB file.
[tester::#YG4] master: $ redis-cli SET foo 123
[tester::#YG4] master: Sent bytes: "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n123\r\n"
[tester::#YG4] master: $ redis-cli SET bar 456
[tester::#YG4] master: Sent bytes: "*3\r\n$3\r\nSET\r\n$3\r\nbar\r\n$3\r\n456\r\n"
[tester::#YG4] master: $ redis-cli SET baz 789
[tester::#YG4] master: Sent bytes: "*3\r\n$3\r\nSET\r\n$3\r\nbaz\r\n$3\r\n789\r\n"
[tester::#YG4] Getting key foo
[tester::#YG4] client: $ redis-cli GET foo
[tester::#YG4] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[your_program] Packet("*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n")
[tester::#YG4] client: Received bytes: "$-1\r\n"
[tester::#YG4] client: Received RESP null bulk string: "$-1\r\n"
[tester::#YG4] Retrying... (1/5 attempts)
[tester::#YG4] client: $ redis-cli GET foo
[tester::#YG4] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[your_program] Packet("*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n")
[tester::#YG4] client: Received bytes: "$-1\r\n"
[tester::#YG4] client: Received RESP null bulk string: "$-1\r\n"
[tester::#YG4] Retrying... (2/5 attempts)
[tester::#YG4] client: $ redis-cli GET foo
[tester::#YG4] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[tester::#YG4] client: Received bytes: "$-1\r\n"
[tester::#YG4] client: Received RESP null bulk string: "$-1\r\n"
[your_program] Packet("*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n")
[tester::#YG4] Retrying... (3/5 attempts)
[tester::#YG4] client: $ redis-cli GET foo
[tester::#YG4] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[your_program] Packet("*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n")
[tester::#YG4] client: Received bytes: "$-1\r\n"
[tester::#YG4] client: Received RESP null bulk string: "$-1\r\n"
[tester::#YG4] Retrying... (4/5 attempts)
[tester::#YG4] client: $ redis-cli GET foo
[tester::#YG4] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[your_program] Packet("*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n")
[tester::#YG4] client: Received bytes: "$-1\r\n"
[tester::#YG4] client: Received RESP null bulk string: "$-1\r\n"
[tester::#YG4] Retrying... (5/5 attempts)
[tester::#YG4] client: $ redis-cli GET foo
[tester::#YG4] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[your_program] Packet("*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n")
[tester::#YG4] client: Received bytes: "$-1\r\n"
[tester::#YG4] client: Received RESP null bulk string: "$-1\r\n"
[tester::#YG4] Expected simple string or bulk string, got NIL
[tester::#YG4] Test failed
[tester::#YG4] Terminating program
[your_program] =INFO REPORT==== 31-May-2024::16:47:35.512094 ===
[your_program] SIGTERM received - shutting down
[your_program]
[tester::#YG4] Program terminated successfully

And here is a snippet of my code:

pub fn main() {
  let state = state.init()
  let port =
    state.get_config(state)
    |> config.get_port()

  let assert Ok(_) =
    glisten.handler(fn(_conn) { #(state, None) }, loop)
    |> glisten.serve(port)

  process.sleep_forever()
}

fn loop(
  msg: Message(BitArray),
  state: State,
  conn: Connection(BitArray),
) -> Next(Message(BitArray), State) {
  io.debug(msg)
  case msg {
    glisten.Packet(data) -> handle_message(data, state, conn)
    glisten.User(_) -> actor.continue(state)
  }
}

fn handle_message(
  msg: BitArray,
  state: State,
  conn: Connection(BitArray),
) -> Next(Message(BitArray), State) {
  let assert Ok(data) = resp.parse(msg)

  case command.from_resp_data(data) {
    Ok(command) -> handle_command(command, state, conn)

    Error(error) -> handle_command_error(error)
  }
}

From what I understand from the logs, the Replica successfully handshakes with the Master. However, neither the Master nor the Replica receives the SET commands (seeing as the only packets logged are for the subsequent GET commands).

Not sure if the GET commands is sent to the Master or the Replica, but in any case the fact that neither is receiving the SET commands is puzzling me.

@korokd these commands are propagated on the replication connection, i.e. the same one used for the handshake (not from a regular client). Can’t tell from the code snippet whether you’re listening on the replication connection or not.

If the info above doesn’t help, could you publish your code to GitHub pease? One of us can take a closer look. More on how to do this here: Publish to GitHub - CodeCrafters

@rohitpaulk Indeed I was expecting to receive the messages on the replicas as if they were regular clients.

After looking more at the Code Example available for this step on Gleam and asking some questions to the folks over on the Gleam Discord I was able to figure out that:

  1. As you mentioned, I should expect the replication messages from the connection that made the handshake and
  2. I needed to do the handshake and listening in a separate process to be able to actively listen to the socket created
1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.