# Commands propagated but not executed in replica (#YG4)

**URL:** <https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144>\
**Category:** Challenges\
**Tags:** challenge:redis\
**Created:** [April 18, 2024, 3:55pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144 "2024-04-18T15:55:35Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![rghdrizzle](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rghdrizzle/32/127_2.png) [@rghdrizzle](https://forum.codecrafters.io/u/rghdrizzle)\
**Post date:** [April 18, 2024, 3:55pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/1 "2024-04-18T15:55:35Z")

</div>

I have been stuck in this challenge , I send the commands from the master to the repplica but the replica after getting them does not execute them even when I have functions to read the commands from the master and then process and execute

```go
package main

import (
	"encoding/hex"
	"fmt"
	"io"
	"net"
	"os"
	"strings"
	"time"
  	"reflect"
)

type Item struct {
	Value string
	Expiry time.Time
}
type ReplicaConfig struct {
	MasterPort string
	MasterHostname string
	SlavePort string
	SlaveAddr string
}
type RedisConfig struct {
	Role string
	Master_rep_ID string
	Master_Offset int
	ReplicaCon ReplicaConfig
}

var config RedisConfig
var m = make(map[string]Item)

const emptyRDBcontent = "524544495330303131fa0972656469732d76657205372e322e30fa0a72656469732d62697473c040fa056374696d65c26d08bc65fa08757365642d6d656dc2b0c41000fa08616f662d62617365c000fff06e3bfec0ff5aa2" // hex
var replica []net.Conn = []net.Conn{}

func main() {

	fmt.Println("Logs from your program will appear here!")
	var portNumber string
	var argArray []string
	argArray = os.Args[1:]
	portNumber = "6379"
	config.Role = "master"
	config.Master_Offset = 0
	config.Master_rep_ID = "8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb"
	if len(argArray) >= 2 {
		if argArray[0] == "--port" {
			portNumber = argArray[1]
		}
		if len(argArray) > 2 {
			if argArray[2] == "--replicaof" {
				config.Role = "slave"
				config.ReplicaCon.MasterPort = argArray[4]
				config.ReplicaCon.MasterHostname = argArray[3]
				config.ReplicaCon.SlavePort = portNumber

			}
		}

	}
	l, err := net.Listen("tcp", "0.0.0.0:"+portNumber)
	if err != nil {
		fmt.Println("Failed to bind to port " + portNumber)
		os.Exit(1)
	}
	if config.Role == "slave" {
		handleHandShaketoMaster()
	}
	for { // infinite loop which accepts multiple connections
		conn, err := l.Accept() // connect to the server using redis-cli client
		if err != nil {
			fmt.Println("Error accepting connection: ", err.Error())
			os.Exit(1)
		}

    
		go handleConn(conn) // a go routine which is responsible to handle for a particular connection
	}
}

func handleConn(conn net.Conn) {
	defer conn.Close() // Close the connection once the functions ends
	for { // infinite loop to send multiple requests to the server from the same client or connection.
		buf := make([]byte, 1024)
		_, err := conn.Read(buf)
		if err != nil {
			conn.Write([]byte("-ERROR\r\n"))
			return
		}
		if err == io.EOF { // if client didnt send anything then return.
			return
		}
		cmd, args, maps := parseCommand(string(buf)) // the input given here has to be in the form of RESP which is a protocol used by Redis
		res := processCommands(cmd, args, maps, config)
		fmt.Println(res)
		fmt.Println(maps)
		_, err = conn.Write([]byte(res))
		if cmd == "PSYNC" {
			rdbcontent, _ := hex.DecodeString(emptyRDBcontent)
			fmt.Println(emptyRDBcontent)
			fmt.Println(rdbcontent)
			_, err = conn.Write([]byte(fmt.Sprintf("$%d\r\n%s", len(rdbcontent), rdbcontent)))
			if err != nil {
				panic(err)
			}
			replica = append(replica, conn)

		}

	}
}
func parseCommand(req string) (string, []string, map[string]Item) {
	tokens := strings.Split(req, "\r\n")
	tokens = tokens[1:]
	cmd := tokens[1]
	fmt.Println(cmd)
	tokens = tokens[2:]
	var args []string
	for _, token := range tokens {
		if !strings.HasPrefix(token, "$") && !strings.HasPrefix(token, "*") {
			args = append(args, token)
		}
	}
	return cmd, args, m
}
func handleHandShaketoMaster() {
	addr := config.ReplicaCon.MasterHostname + ":" + config.ReplicaCon.MasterPort

	conn, err := net.Dial("tcp", addr)
	if err != nil {
		panic(err.Error())
	}
	sendCommand("*1\r\n$4\r\nping\r\n", conn)
	sendCommand("*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n", conn)
	sendCommand("*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n", conn)
	sendCommand("*3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n", conn)
	//replica = conn
  go handlePropagatedCommands(conn)

}
func handlePropagatedCommands(conn net.Conn){
	defer conn.Close()
  for {
		buf := make([]byte, 1024)
		_, err := conn.Read(buf)
		if err != nil {
			conn.Write([]byte("-ERROR\r\n"))
			return
		}
		if err == io.EOF { // if client didnt send anything then return.
			return
		}
		cmd, args, maps := parseCommand(string(buf)) // the input given here has to be in the form of RESP which is a protocol used by Redis
		res := processCommands(cmd, args, maps, config)
    fmt.Println(res)
}
}
func sendCommand(req string, conn net.Conn) {
	_, err := conn.Write([]byte(req))
	if err != nil {
		panic(err)
	}
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err != nil {
		fmt.Println("Error reading from connection: ", err.Error())
		os.Exit(1)
	}
	fmt.Println(n)
}
func processCommands(cmd string, arg []string, m map[string]Item, config RedisConfig) string {
	cmd = strings.ToLower(cmd)
  if config.Role == "slave"{
    fmt.Println("Slave is running now ")
    fmt.Println(cmd)

  }
	if cmd == "ping" {
		return "+PONG\r\n"
	} else if cmd == "echo" {
		return "+" + arg[0] + "\r\n"
	} else if cmd == "set" {
		if strings.ToLower(arg[2]) != "px" {
			m[arg[0]] = Item{Value: arg[1]}
			sendToSlave(cmd, arg[0], arg[1])
			return "+OK\r\n"
		}
		if strings.ToLower(arg[2]) == "px" {
			duration, _ := time.ParseDuration(arg[3] + "ms")
			m[arg[0]] = Item{Value: arg[1], Expiry: time.Now().Add(duration)}
			return "+OK\r\n"
		}
	} else if cmd == "get" {
		if val, ok := m[arg[0]]; ok {
			if val.Expiry.IsZero() || val.Expiry.After(time.Now()) {
				return "$" + fmt.Sprint(len(val.Value)) + "\r\n" + val.Value + "\r\n"
			}
			delete(m, arg[0])
		}
	} else if strings.ToUpper(cmd) == "INFO" {
		if arg[0] == "replication" {
			role := fmt.Sprintf("\r\nrole:%s", config.Role)
			mas_rep_ID := "\r\n" + "master_replid:" + config.Master_rep_ID
			mas_offset := "\r\n" + "master_repl_offset:" + fmt.Sprint(config.Master_Offset)
			res := role + mas_rep_ID + mas_offset
			return "$" + fmt.Sprint(len(res)) + "\r\n" + res + "\r\n"
		}
	} else if cmd == "replconf" {
		if arg[0] == "listening-port" {
			// check if the resp is valid
			return "+OK\r\n"
		}
		if arg[0] == "capa" {
			//check if the resp is valid
			return "+OK\r\n"
		}
	} else if cmd == "psync" {
		msg := "+FULLRESYNC" + " " + config.Master_rep_ID + " " + fmt.Sprint(config.Master_Offset) + "\r\n"
    	return msg
	} else if cmd == "type" {
    val, ok := m[arg[0]]
    if ok{
      typeOfVariable := reflect.TypeOf(val.Value)
	  res := fmt.Sprintf("+%s\r\n",typeOfVariable)
      return res
    }
    
      return "+none\r\n"
  }
	return "$-1\r\n"
}
func toRespArrays(arr []string) string {
	res := fmt.Sprintf("*%d\r\n", len(arr))
	for _, element := range arr {
		// add elements in RESP format
		res += fmt.Sprintf("$%d\r\n%s\r\n", len(element), element)
	}
	return res
}
func sendToSlave(cmd string, key string, value string) {
	if replica != nil && config.Role=="master"{
		for _, slave := range replica {
			_, err := slave.Write([]byte(toRespArrays([]string{cmd, key, value})))
			if err != nil {
				panic(err)
			}
		}
	}
}

```

---

<div class="post-metadata">

**Author:** ![rohitpaulk](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rohitpaulk/32/6_2.png) [@rohitpaulk](https://forum.codecrafters.io/u/rohitpaulk)\
**Post date:** [April 18, 2024, 4:38pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/2 "2024-04-18T16:38:17Z")

</div>

@rghdrizzle could you share your logs (with debug mode turned on)? More on how to enable debug mode here: [How do I debug test failures? - CodeCrafters](https://docs.codecrafters.io/challenges/debug-test-failures#1-turn-on-debug-mode)

---

<div class="post-metadata">

**Author:** ![rghdrizzle](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rghdrizzle/32/127_2.png) [@rghdrizzle](https://forum.codecrafters.io/u/rghdrizzle)\
**Post date:** [April 26, 2024, 2:22pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/3 "2024-04-26T14:22:07Z")

</div>

![Screenshot (245)](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/1X/8029cc6e540e90195c37921eb01987866218a302.png)  
 ![Screenshot (246)](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/1X/d0d8567a86602a98773b3f517c1fb85f53916b9a.png)  
 ![Screenshot (247)](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/1X/28d37668ba64358ac0ac9daa625637b2677098aa.png)  
 ![Screenshot (248)](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/1X/438935bc8fd52c85ae191fda6e204b842405103b.png)  
Here is the output I got

---

<div class="post-metadata">

**Author:** ![rohitpaulk](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rohitpaulk/32/6_2.png) [@rohitpaulk](https://forum.codecrafters.io/u/rohitpaulk)\
**Post date:** [April 26, 2024, 6:32pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/4 "2024-04-26T18:32:30Z")

</div>

@rghdrizzle thanks! I’d recommend logging inside `handlePropagatedCommands` at this point:

```go
        buf := make([]byte, 1024)
		_, err := conn.Read(buf)
		if err != nil {
			conn.Write([]byte("-ERROR\r\n"))
			return
		}

```

I think if we know what’s being received in `buf` it’ll be more clear what’s going on here.

---

<div class="post-metadata">

**Author:** ![rghdrizzle](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rghdrizzle/32/127_2.png) [@rghdrizzle](https://forum.codecrafters.io/u/rghdrizzle)\
**Post date:** [April 27, 2024, 4:59pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/5 "2024-04-27T16:59:44Z")

</div>

ok here is the output Im getting now

 ![Screenshot (257)](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/1X/10e853422fc148f39e8ff38467740157387cb80b.png)

---

<div class="post-metadata">

**Author:** ![rghdrizzle](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rghdrizzle/32/127_2.png) [@rghdrizzle](https://forum.codecrafters.io/u/rghdrizzle)\
**Post date:** [April 28, 2024, 3:23pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/6 "2024-04-28T15:23:29Z")

</div>

# UPDATE

Im getting three different outputs sometimes  
One instance Im getting an output similar to the image sent above and then the below images are the outputs I get time to time. The first image below shows me that the set commands are all sent together in the same buffer and the last image I have no idea why the connection gets broken.

 ![Screenshot (258)](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/1X/b782c0713cf2afc31c2133a97dd9e14219c21ba1.png)  
 ![Screenshot (259)](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/1X/1fed4a74503b166de656668cfaa2a9e4886353f5.png)

---

<div class="post-metadata">

**Author:** ![rohitpaulk](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rohitpaulk/32/6_2.png) [@rohitpaulk](https://forum.codecrafters.io/u/rohitpaulk)\
**Post date:** [May 4, 2024, 1:20pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/7 "2024-05-04T13:20:13Z")

</div>

We’re going to improve our logs here + we’ll intentionally send all SETs in a single write call so the behaviour is consistent and not timing-dependent. Will keep open until that’s done!

---

<div class="post-metadata">

**Author:** ![rghdrizzle](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rghdrizzle/32/127_2.png) [@rghdrizzle](https://forum.codecrafters.io/u/rghdrizzle)\
**Post date:** [May 5, 2024, 3:55pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/8 "2024-05-05T15:55:04Z")

</div>

So I will have to split all those SET commands into separate commands and then process the commands ?

---

<div class="post-metadata">

**Author:** ![rohitpaulk](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rohitpaulk/32/6_2.png) [@rohitpaulk](https://forum.codecrafters.io/u/rohitpaulk)\
**Post date:** [May 6, 2024, 1:57pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/9 "2024-05-06T13:57:09Z")

</div>

@rghdrizzle yep, correct (this mimics what a real Redis server would have to do)

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/3X/7/0/700657133935c15703e22c7c8870394f6e6dc27d.svg) [@system](https://forum.codecrafters.io/u/system)\
**Post date:** [June 4, 2024, 3:30am UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/11 "2024-06-04T03:30:49Z")

</div>

Note: I’ve updated the title of this post to include the stage ID (#YG4). You can learn about the stages rename here: [Upcoming change: Stages overhaul](https://forum.codecrafters.io/t/upcoming-change-stages-overhaul/375).

---

<div class="post-metadata">

**Author:** ![rohitpaulk](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/rohitpaulk/32/6_2.png) [@rohitpaulk](https://forum.codecrafters.io/u/rohitpaulk)\
**Post date:** [June 18, 2024, 12:14pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/12 "2024-06-18T12:14:32Z")

</div>

We’re still noodling on what changes to make here - whether we should send all `SET` commands at once, or whether we should send a combination (one SET command direct, and the others as a group).

Thought I’d leave a quick note to mention what’s pending.

---

<div class="post-metadata">

**Author:** ![andy1li](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/andy1li/32/10_2.png) [@andy1li](https://forum.codecrafters.io/u/andy1li)\
**Post date:** [October 8, 2024, 1:13pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/13 "2024-10-08T13:13:14Z")

</div>

We haven’t changed the tester behaviour itself, but this is now documented in the instructions!

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/3X/7/0/700657133935c15703e22c7c8870394f6e6dc27d.svg) [@system](https://forum.codecrafters.io/u/system)\
**Post date:** [October 13, 2024, 1:14pm UTC](https://forum.codecrafters.io/t/commands-propagated-but-not-executed-in-replica-yg4/144/14 "2024-10-13T13:14:15Z")

</div>

Closed on October 13, 2024, 1:14pm UTC

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