I’m stuck on Stage 21: Get ACK With No commands.
My problem is that I am unable to receive to consistently receive the FULLRESYNC command, the RDB File, and the GETACK command from the master. I have tried logging these commands from the master to the replica and I have noticed something interesting. Sometimes when I rerun the tester, I am able to log the FULLRESYNC command and the RDB File, other times I am able to log just the FULLRESYNC command (not the RDB File), and other times I am unable to receive any commands at all. I have never received the GETACK command, though. I suspect this has something to do with race conditions, but I can’t figure out how to resolve this issue. I also have noticed that these logs appear after the test fails for some reason, which makes me unable to send the appropriate replica response to the GETACK command.
Here are some examples of the logs I have been receiving:
This is an example of the replica receiving the FULLRESYNC command
This is an example of the log only receiving the buffer length and nothing else below that.
remote: Running tests on your code. Logs should appear shortly...
remote:
remote: [tester::#XV6] Running tests for Stage #XV6 (Replication - ACKs with no commands)
remote: [tester::#XV6] Master is running on port 6379
remote: [tester::#XV6] $ ./spawn_redis_server.sh --port 6380 --replicaof "localhost 6379"
remote: [your_program] Logs from your program will appear here!
remote: [tester::#XV6] master: Waiting for replica to initiate handshake with "PING" command
remote: [your_program] Connected to master
remote: [tester::#XV6] Received ["PING"]
remote: [tester::#XV6] master: Sent "PONG"
remote: [tester::#XV6] master: Waiting for replica to send "REPLCONF listening-port 6380" command
remote: [your_program] Buffer Length 7
remote: [your_program] Raw data received: +PONG
remote: [your_program]
remote: [your_program] Received message: +PONG
remote: [your_program] Parsed response: +PONG
remote: [your_program] End of data processing block
remote: [tester::#XV6] Received ["REPLCONF", "listening-port", "6380"]
remote: [tester::#XV6] master: Sent "OK"
remote: [tester::#XV6] master: Waiting for replica to send "REPLCONF capa" command
remote: [tester::#XV6] Received ["REPLCONF", "capa", "psync2"]
remote: [your_program] Buffer Length 5
remote: [your_program] Raw data received: +OK
remote: [your_program]
remote: [your_program] Received message: +OK
remote: [your_program] Parsed response: +OK
remote: [your_program] End of data processing block
remote: [tester::#XV6] master: Sent "OK"
remote: [tester::#XV6] master: Waiting for replica to send "PSYNC" command
remote: [tester::#XV6] Received ["PSYNC", "?", "-1"]
remote: [your_program] Buffer Length 5
remote: [your_program] Raw data received: +OK
remote: [your_program]
remote: [your_program] Received message: +OK
remote: [your_program] Parsed response: +OK
remote: [your_program] End of data processing block
remote: [tester::#XV6] master: Sent "FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0"
remote: [tester::#XV6] Sent RDB file.
remote: [tester::#XV6] master: > REPLCONF GETACK *
remote: [tester::#XV6] Expected command to be "replconf", got "psync"
remote: [tester::#XV6] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)
remote: [your_program] Buffer Length 148
And this is an example of logging both the FULLRESYNC command and the RDB File, but not the GETACK command.
remote: Running tests on your code. Logs should appear shortly...
remote:
remote: [tester::#XV6] Running tests for Stage #XV6 (Replication - ACKs with no commands)
remote: [tester::#XV6] Master is running on port 6379
remote: [tester::#XV6] $ ./spawn_redis_server.sh --port 6380 --replicaof "localhost 6379"
remote: [your_program] Logs from your program will appear here!
remote: [tester::#XV6] master: Waiting for replica to initiate handshake with "PING" command
remote: [your_program] Connected to master
remote: [tester::#XV6] Received ["PING"]
remote: [tester::#XV6] master: Sent "PONG"
remote: [tester::#XV6] master: Waiting for replica to send "REPLCONF listening-port 6380" command
remote: [your_program] Buffer Length 7
remote: [your_program] Raw data received: +PONG
remote: [your_program]
remote: [your_program] Received message: +PONG
remote: [your_program] Parsed response: +PONG
remote: [your_program] End of data processing block
remote: [tester::#XV6] Received ["REPLCONF", "listening-port", "6380"]
remote: [tester::#XV6] master: Sent "OK"
remote: [tester::#XV6] master: Waiting for replica to send "REPLCONF capa" command
remote: [tester::#XV6] Received ["REPLCONF", "capa", "psync2"]
remote: [your_program] Buffer Length 5
remote: [your_program] Raw data received: +OK
remote: [your_program]
remote: [your_program] Received message: +OK
remote: [your_program] Parsed response: +OK
remote: [your_program] End of data processing block
remote: [tester::#XV6] master: Sent "OK"
remote: [tester::#XV6] master: Waiting for replica to send "PSYNC" command
remote: [tester::#XV6] Received ["PSYNC", "?", "-1"]
remote: [your_program] Buffer Length 5
remote: [your_program] Raw data received: +OK
remote: [your_program]
remote: [your_program] Received message: +OK
remote: [your_program] Parsed response: +OK
remote: [your_program] End of data processing block
remote: [tester::#XV6] master: Sent "FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0"
remote: [tester::#XV6] Sent RDB file.
remote: [tester::#XV6] master: > REPLCONF GETACK *
remote: [tester::#XV6] Expected command to be "replconf", got "psync"
remote: [tester::#XV6] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)
remote: [your_program] Buffer Length 148
remote: [your_program] Raw data received: +FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0
remote: [your_program] $88
remote: [your_program] REDIS0011� redis-ver7.2.0�
remote: [your_program] redis-bits�@�ctime��eused-mem°�
And here’s a snippet of my code:
const net = require("net");
const portIndex = process.argv.indexOf("--port");
const isSlave = process.argv.indexOf("--replicaof");
const PORT = portIndex != -1 ? process.argv[portIndex + 1] : 6379;
const replicas = [];
let masterPort = 0;
if (isSlave != -1) {
masterPort = process.argv[isSlave + 1];
masterPort = masterPort.split("localhost ")[1];
} else {
masterPort = PORT;
}
const replicaDict = {};
let buffer = '';
const client = net.createConnection({ port: masterPort, host: 'localhost' }, () => {
console.log('Connected to master');
client.write("*1\r\n" + getBulkString("PING"));
});
client.on('data', (data) => {
buffer += data.toString('utf8');
console.log("Buffer Length", buffer.length);
console.log('Raw data received:', buffer);
if (buffer.indexOf("FULLRESYNC") != -1) {
console.log("Reached This If/Else Block");
// client.write("*3/r/n" + getBulkString("REPLCONF") + getBulkString("ACK")+ getBulkString("0")); //commented out the replica response
}
let messages = buffer.split('\r\n');
let resData = buffer; // will use to handle the handshake responses
buffer = messages.pop(); // resets the buffer with ""
messages.forEach((message) => {
console.log(`Received message: ${message.trim()}`);
if (message.startsWith('> REPLCONF GETACK')) {
console.log('Received REPLCONF GETACK');
// Handle REPLCONF GETACK message
// Never reaches this block
}
});
if (resData) {
const resp = resData.split('\r\n')[0];
console.log('Parsed response:', resp);
if (resp === "+PONG") {
client.write("*3\r\n" + getBulkString("REPLCONF") + getBulkString("listening-port") + getBulkString(PORT));
client.write("*3\r\n" + getBulkString("REPLCONF") + getBulkString("capa") + getBulkString("psync2"));
} else if (resp === "+OK") {
client.write("*3\r\n" + getBulkString("PSYNC") + getBulkString("?") + getBulkString("-1"));
}
}
console.log("End of data processing block");
});
client.on('end', () => {
console.log('Disconnected from master');
});
client.on('error', (err) => {
if (err.code === 'EPIPE') {
console.error('EPIPE error: attempting to write to a closed stream');
} else {
console.error('Connection error:', err);
}
});
I have found this similar post describing a similar issue that I am having, but I am still unsure on how to implement the solution to that problem.