Help! Stuck on Stage 3 of Redis Challenge (Rust)

I’m getting the following from the logs when I push to master:

remote: [compile]    Compiling redis-starter-rust v0.1.0 (/app)
remote: [compile]     Finished release [optimized] target(s) in 0.78s
remote: [compile] Compilation successful.
remote: 
remote: Debug = true
remote: 
remote: [tester::#WY1] Running tests for Stage #WY1 (Respond to multiple PINGs)
remote: [tester::#WY1] $ ./spawn_redis_server.sh
remote: [your_program] Logs from your program will appear here!
remote: [tester::#WY1] client-1: $ redis-cli PING
remote: [tester::#WY1] client-1: Sent bytes: "*1\r\n$4\r\nPING\r\n"
remote: [your_program] accepted new connection
remote: [your_program] parsing request
remote: [your_program] got ping
remote: [your_program] Finished parsing request
remote: [your_program] Finish handling client
remote: [tester::#WY1] client-1: Received bytes: "+PONG\r\n"
remote: [tester::#WY1] client-1: Received RESP value: "PONG"
remote: [tester::#WY1] Received "PONG"
remote: [tester::#WY1] client-1: $ redis-cli PING
remote: [tester::#WY1] client-1: Sent bytes: "*1\r\n$4\r\nPING\r\n"
remote: [tester::#WY1] Received: "" (no content received)
remote: [tester::#WY1]            ^ error
remote: [tester::#WY1] Error: Expected start of a new RESP2 value (either +, -, :, $ or *)
remote: [tester::#WY1] Test failed
remote: [tester::#WY1] Terminating program
remote: [tester::#WY1] Program terminated successfully
remote: 
remote: View our article on debugging test failures: https://codecrafters.io/debug
remote: 
To https://git.codecrafters.io/26256492f22bbeb6
   8b35942..6bdb7d0  master -> master

And I’m not entirely sure why. When I test locally with the redis-cli or piping the request through netcat it works as expected. And it looks like from the tester it works the first time doing $ redis-cli PING , however the 2nd time no. I also get the same error message using the codecrafters cli tool.

I saw that there was a similar issue for someone else doing Stage 2, and the issue was they weren’t pushing on master but main instead. I’ve checked on my end and the only branch I have is master.

I was also having a similar issue in Stage 2 where I got the Received: "" (no content received), however I just refactored my code and it worked (?)

Not entirely sure what’s going wrong, but any help would be greatly appreciated! I also can share my code if needed.

1 Like

@peter-kuchel Code would be helpful! You can publish to GitHub to make this easy: Publish to GitHub - CodeCrafters

Hey @rohitpaulk , thanks for the quick response! Here is the repo on github: GitHub - peter-kuchel/codecrafters-redis-rust: Codecrafters Redis in Rust

Hey @peter-kuchel, for this stage you’ll need a loop within handle_new_conn.

Example diff that passes tests:

diff --git a/src/main.rs b/src/main.rs
index 5b163fd..62744d3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,72 +1,71 @@
+use std::io::{self, BufRead, BufReader, BufWriter, Cursor, Seek, SeekFrom, Write};
 use std::net::{TcpListener, TcpStream};
-use std::io::{self, BufReader, BufWriter, BufRead, Cursor, Seek, SeekFrom, Write}; 
 // use std::time::Duration;
 
 struct ClientResp {
-    resps: String
+    resps: String,
 }
 
-fn handle_cmds(cmd: &String, client_resp: &mut ClientResp){
-
+fn handle_cmds(cmd: &String, client_resp: &mut ClientResp) {
     let mut _cmd: String = cmd.to_lowercase();
-    let cmd_str: &str = _cmd.trim(); 
+    let cmd_str: &str = _cmd.trim();
 
     match cmd_str {
-        "ping"=> {
+        "ping" => {
             println!("got ping");
             client_resp.resps.push_str("+PONG\r\n");
             // let _resp: &str = "+PONG\r\n";
             // stream_writer.write(resp.as_bytes()).expect("Write went wrong");
-        },
+        }
 
-        _ => { println!("cmd not recognized: {}", cmd_str); } 
+        _ => {
+            println!("cmd not recognized: {}", cmd_str);
+        }
     }
 }
 
-
-fn parse_client_req(stream_reader: &mut BufReader<TcpStream>, client_resp: &mut ClientResp) -> io::Result<()>{
+fn parse_client_req(
+    stream_reader: &mut BufReader<TcpStream>,
+    client_resp: &mut ClientResp,
+) -> io::Result<()> {
     println!("parsing request");
 
-    let req_buf: &[u8] = stream_reader.fill_buf().unwrap(); 
+    let req_buf: &[u8] = stream_reader.fill_buf().unwrap();
 
-    let mut _line = String::new(); 
+    let mut _line = String::new();
     let mut req_curs = Cursor::new(req_buf);
 
     let cursor_size: usize = req_curs.seek(SeekFrom::End(0)).unwrap() as usize;
     req_curs.seek(SeekFrom::Start(0)).unwrap();
-    
-    let mut curr_pos: usize; 
-
-    // parse req from the cursor on each new line 
-    loop{ 
-        
-        curr_pos = req_curs.position() as usize; 
- 
-        if curr_pos == cursor_size{
-            println!("Finished parsing request"); 
+
+    let mut curr_pos: usize;
+
+    // parse req from the cursor on each new line
+    loop {
+        curr_pos = req_curs.position() as usize;
+
+        if curr_pos == cursor_size {
+            println!("Finished parsing request");
             break;
         }
-        
-        req_curs.read_line(&mut _line).unwrap(); // reading from cursor won't fail 
 
-        let line_bytes: &[u8] = _line.as_bytes();
-        let _type: u8  = line_bytes[0];
+        req_curs.read_line(&mut _line).unwrap(); // reading from cursor won't fail
 
+        let line_bytes: &[u8] = _line.as_bytes();
+        let _type: u8 = line_bytes[0];
 
         match _type {
-            // Bulk String 
+            // Bulk String
             0x24 => {
-
-                _line.clear(); 
-                req_curs.read_line(&mut _line).unwrap(); 
+                _line.clear();
+                req_curs.read_line(&mut _line).unwrap();
 
                 _line = _line.replace("\r\n", "");
 
                 handle_cmds(&_line, client_resp);
+            }
 
-            }, 
-
-            // Array 
+            // Array
             0x2a => {
                 // get array size
             }
@@ -80,51 +79,53 @@ fn parse_client_req(stream_reader: &mut BufReader<TcpStream>, client_resp: &mut
     }
 
     Ok(())
-
 }
 
-fn handle_new_conn(stream: TcpStream) -> io::Result<()>{
+fn handle_new_conn(stream: TcpStream) -> io::Result<()> {
+    let write_stream: TcpStream = stream
+        .try_clone()
+        .expect("cloning the client tcp stream failed");
 
-    let write_stream: TcpStream = stream.try_clone().expect("cloning the client tcp stream failed");
+    loop {
+        let mut client_resp = ClientResp {
+            resps: String::with_capacity(1 << 8),
+        };
+        let mut stream_reader: BufReader<TcpStream> = BufReader::new(stream.try_clone().unwrap());
 
-    let mut client_resp = ClientResp { resps: String::with_capacity( 1 << 8 ), };
-    let mut stream_reader: BufReader<TcpStream> = BufReader::new(stream);
-    
+        let _resp_res = parse_client_req(&mut stream_reader, &mut client_resp);
 
-    let _resp_res = parse_client_req( &mut stream_reader, &mut client_resp);
+        // handle sending everything back to the client now
+        {
+            let mut stream_writer: BufWriter<TcpStream> =
+                BufWriter::new(write_stream.try_clone().unwrap());
+            let mut resp_curs: Cursor<String> = Cursor::new(client_resp.resps);
+            let curs_size: u64 = resp_curs.seek(SeekFrom::End(0)).unwrap();
+            resp_curs.seek(SeekFrom::Start(0)).unwrap();
 
-    // handle sending everything back to the client now 
-    {
-        let mut stream_writer: BufWriter<TcpStream> = BufWriter::new(write_stream);
-        let mut resp_curs: Cursor<String> = Cursor::new(client_resp.resps);
-        let curs_size: u64 = resp_curs.seek(SeekFrom::End(0)).unwrap();
-        resp_curs.seek(SeekFrom::Start(0)).unwrap();
+            let mut resp_line = String::new();
 
+            while curs_size != resp_curs.position() {
+                resp_curs.read_line(&mut resp_line)?;
 
-        let mut resp_line = String::new();
-
-        while curs_size != resp_curs.position() {
-            
-            resp_curs.read_line(&mut resp_line)?;
+                stream_writer.write(resp_line.as_bytes())?;
+                stream_writer.flush()?;
+                resp_line.clear();
+            }
+        }
 
-            stream_writer.write(resp_line.as_bytes())?;
-            stream_writer.flush()?;
-            resp_line.clear();
+        if _resp_res.is_err() {
+            break;
         }
-        
     }
-    
-    Ok(())
-    
 
+    Ok(())
 }
 
 fn main() -> io::Result<()> {
-    
     println!("Logs from your program will appear here!");
 
     let listener = TcpListener::bind("127.0.0.1:6379").unwrap();
-    
+
     for stream in listener.incoming() {
         match stream {
             Ok(_stream) => {

(Please ignore the formatting stuff, rustfmt ended up changing a lot of lines)

The important change is the loop within handle_new_conn.

Ahhh okay, oh wow honestly I should have dug into it more, seems like something I could have solved haha. Anyways, thank you so much! @rohitpaulk

1 Like

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