Issues with testing but working locally #eh4

I’m stuck on Stage #eh4

I’ve tried my changes locally and things seem to work there but it is failing in the tests.

Local Log Master →

 go run .
Logs from your program will appear here!
0.0.0.0:6379
*1\r\n$4\r\nPING\r\n
[PING]
*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n
[REPLCONF listening-port 6380]
*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n
[REPLCONF capa psync2]

Local logs from slave:

go run . --replicaof "localhost 6379" --port 6380
Logs from your program will appear here!
payload given -> *1\r\n$4\r\nPING\r\n
got response <-  +PONG

starting replica conf port 6380
payload given -> *3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n
got response <-  +OK

starting replica conf psync
payload given -> *3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n
got response <-  +OK

0.0.0.0:6380

Logs from test:

[tester::#EH4] Running tests for Stage #EH4 (Replication - Send handshake (2/3))
[tester::#EH4] Master is running on port 6379
[tester::#EH4] $ ./spawn_redis_server.sh --port 6380 --replicaof "localhost 6379"
[your_program] Logs from your program will appear here!
[tester::#EH4] master: Waiting for replica to initiate handshake with "PING" command
[your_program] payload given -> *1\r\n$4\r\nPING\r\n
[tester::#EH4] master: Received bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#EH4] master: Received RESP array: ["PING"]
[tester::#EH4] Received ["PING"]
[tester::#EH4] master: Sent "PONG"
[tester::#EH4] master: Sent bytes: "+PONG\r\n"
[tester::#EH4] master: Waiting for replica to send "REPLCONF listening-port 6380" command
[your_program] got response <-  +PONG
[your_program] 
[your_program] starting replica conf port 6380
[your_program] payload given -> *3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n
[tester::#EH4] Received: "" (no content received)
[tester::#EH4]            ^ error
[tester::#EH4] Error: Expected start of a new RESP2 value (either +, -, :, $ or *)
[tester::#EH4] Test failed
[tester::#EH4] Terminating program
[tester::#EH4] Program terminated successfully

And here’s part of my relevant code:

response_generator.go (used by master here)

var responseFunc map[string]func([]string) *ResponseStruct = map[string]func([]string) *ResponseStruct{
	"ECHO":     echoResp,
	"PING":     pingResp,
	"SET":      setResp,
	"GET":      getResp,
	"INFO":     infoResp,
	"REPLCONF": replConf,
}

func replConf(params []string) *ResponseStruct {
	return &ResponseStruct{
		data:          "OK",
		type_response: "simple-string",
	}
}

slave.go

func InitSlave(masterURL string, slavePort int) *Slave {
	storage.InitInfoMap("slave")
	masterURLArray := strings.Split(masterURL, " ")
	masterHost, masterPort := masterURLArray[0], masterURLArray[1]
	masterLink := fmt.Sprintf("%s:%s", masterHost, masterPort)
	slaveObj := &Slave{masterHost: masterHost, masterPort: masterPort, masterLink: masterLink, slavePort: slavePort}
	err := slaveObj.PingMaster()
	if err != nil {
		panic(err)
	}
	fmt.Println("starting replica conf port", slaveObj.slavePort)
	err = slaveObj.ReplicaConfPort()
	if err != nil {
		panic(err)
	}
	fmt.Println("starting replica conf psync")
	err = slaveObj.ReplicaConfPsync()
	if err != nil {
		panic(err)
	}
	return slaveObj
}

func (s *Slave) ReplicaConfPort() error {
	link := fmt.Sprintf("%s:%s", s.masterHost, s.masterPort)
	payload := fmt.Sprintf("*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n%d\r\n", s.slavePort)
	err := dialMaster(link, payload)
	if err != nil {
		return err
	}
	return nil
}

func (s *Slave) ReplicaConfPsync() error {
	link := fmt.Sprintf("%s:%s", s.masterHost, s.masterPort)
	payload := "*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n"
	err := dialMaster(link, payload)
	if err != nil {
		return err
	}
	return nil
}

I’ve just run tests against your code, but somehow the code cannot pass an earlier stage The INFO command on a replica #hc6 anymore.

You can use codecrafters test --previous to run all previous stages. It might be better to fix the earlier stages first.

Did you get past this error @OptimusPrimuser? I’m having the same problem with EH4 (JavaScript).

** Update **
Resolved the issue using a single TCP client for all the handshake calls. My previous code was creating and closing a connection for each handshake call.

2 Likes

@joelburger Just took a look at the output from your code.

It seems that the code was opening a new connection to the master, every time it wanted to send something, resulting in:

  1. A hanging handshake for the first connection, waiting for later steps.
  2. A malformed handshake for the second connection, lacking the first step.

Try maintaining just one connection to the master, and send everything through it.

EDIT: Looks like my post and your update happened at about the same time. :raised_hands:

2 Likes