Problem
data = self.request.recv(1024)
...
tokens = CommandParser.parse(data)
No buffering loop across multiple recv() calls. Two concrete failure modes:
Oversized payload: any KESP command over 1024 bytes (long HSET value, big LPUSH arg list) gets cut mid-frame → either a bogus -ERR Malformed KESP payload on a valid command, or a misparse depending on where the cut lands.
Pipelined commands in one read: if two small commands arrive in a single TCP segment, CommandParser.parse only consumes the first declared array and silently drops the rest — no error, no response, command just vanishes.
Fix:
Maintain a per-connection byte buffer. Loop recv() until you have a complete frame (use the declared array/string lengths to know when you do), then hand off only the complete frame to the parser, and retain any leftover bytes for the next iteration. This is the standard fix for any from-scratch socket protocol — Kedis's KESP format already carries explicit length prefixes, which makes this straightforward to implement correctly.
Problem
No buffering loop across multiple recv() calls. Two concrete failure modes:
Oversized payload: any KESP command over 1024 bytes (long HSET value, big LPUSH arg list) gets cut mid-frame → either a bogus -ERR Malformed KESP payload on a valid command, or a misparse depending on where the cut lands.
Pipelined commands in one read: if two small commands arrive in a single TCP segment, CommandParser.parse only consumes the first declared array and silently drops the rest — no error, no response, command just vanishes.
Fix:
Maintain a per-connection byte buffer. Loop recv() until you have a complete frame (use the declared array/string lengths to know when you do), then hand off only the complete frame to the parser, and retain any leftover bytes for the next iteration. This is the standard fix for any from-scratch socket protocol — Kedis's KESP format already carries explicit length prefixes, which makes this straightforward to implement correctly.