redis-rs 2 RC로 옮길 때, HMGET의 누락 필드는 어떻게 처리할까?
요청한 필드 하나가 비었다는 이유로 HMGET 호출 전체가 실패한다. Redis는 정상 응답을 보냈는데, redis-rs 2에서는 빈 필드가 어떤 값으로 들어올까?

- redis-rs 2 후보 버전은 일부 타입 지정 명령의 반환값을 항목별 Option으로 고친다.
- 목록 전체가 없다는 의미와 목록 안의 특정 값이 없다는 의미를 호출 코드에서 구별해야 한다.
- 숫자 변환도 엄격해져, TTL의 음수 응답을 u64로 받던 코드는 컴파일 뒤 실제 실행에서 오류를 만날 수 있다.
HMGET의 정상 응답을 Rust 타입이 담지 못했다
redis-rs 2 RC에서는 타입이 정해진 hmget의 결과가 Vec<Option<String>>으로 바뀐다. 여러 필드 중 없는 필드는 None으로 받을 수 있다. 기존의 Vec<String>은 문자열이 없는 자리를 표현하지 못했다.
Redis의 HMGET 명세는 요청한 필드 순서대로 값을 반환하고, 없는 필드의 자리에는 nil을 넣도록 한다. 해시 자체가 없으면 요청한 필드 수만큼 nil이 나온다. 일부 필드가 빠져 있는 상태는 이 명령이 원래 표현할 수 있는 결과다.
8월에 올라온 사용자 이슈는 redis 1.5.0의 타입 지정 API에서 그 차이를 지적했다. 필드 하나라도 없으면 응답을 문자열로 바꾸는 과정에서 전체 호출이 실패한다는 내용이다. 개발자가 알린 2 RC 소식은 이런 선택적 반환 타입의 수정을 주요 변화로 내세웠다.
목록 바깥의 Option과 항목 안의 Option은 다르다
변경 대상은 TypedCommands와 비동기판 AsyncTypedCommands의 일부 메서드다. 개발자가 반환 타입을 직접 선택하는 일반 Commands API와 구분해야 한다. 공식 마이그레이션 문서의 반환 타입 변경은 다음과 같다.
| 메서드 | 기존 성공값 | 2 RC의 성공값 |
|---|---|---|
| hmget | Vec<String> | Vec<Option<String>> |
| hget_ex | Vec<String> | Vec<Option<String>> |
| zscore_multiple | Option<Vec<f64>> | Vec<Option<f64>> |
| geo_hash | Vec<String> | Vec<Option<String>> |
예를 들어 프로필에서 name과 city를 순서대로 요청했고 이름만 저장돼 있다고 가정하자. 새 반환 구조에서는 첫 항목에 이름을 담고 두 번째 항목을 None으로 표현할 수 있다.
호출부는 각 항목을 처리해야 한다. 빈 문자열로 저장된 값과 필드 자체가 없는 값은 서로 다른 상태다. None을 무조건 빈 문자열로 치환하면 앱이 필요로 하는 구분이 사라질 수 있다. 특히 zscore_multiple은 목록 전체를 한 번 분기하던 코드에서 각 점수의 존재 여부를 살피는 코드로 바뀐다.
TTL을 u64로 받는 코드는 빌드 성공 뒤에도 달라진다
2 RC의 또 다른 변화는 범위를 벗어난 숫자를 변환할 때 오류를 반환한다는 점이다. 기존 FromRedisValue의 일부 숫자 변환은 값이 대상 타입에 맞지 않아도 조용히 다른 숫자로 바꿨다. 따라서 타입 선언을 그대로 둔 채 컴파일되는 코드도 동작 확인이 필요하다.
TTL 명령은 남은 시간을 초로 반환하지만, 키가 없으면 -2, 키에 만료 시각이 없으면 -1을 반환한다. 부호 없는 u64는 이 두 상태를 표현할 수 없다. 마이그레이션 문서는 다음처럼 부호 있는 타입으로 받는 방식을 제시한다.
let ttl: i64 = con.ttl("key")?; 그다음 -2는 키 없음, -1은 만료 설정 없음, 나머지는 남은 초로 분기한다. 단순히 반환값을 시간 길이로 바꾸기 전에 상태부터 읽는 순서다. 음수 응답을 받은 오류를 “Redis 서버가 TTL을 잘못 줬다”는 뜻으로 해석해서는 안 된다.
없는 값과 경계값을 넣어 확인한다
업그레이드를 준비한다면 HMGET에는 모든 필드가 있는 경우, 일부가 없는 경우, 해시 자체가 없는 경우를 넣어 호출부가 의도한 결과를 내는지 확인할 수 있다. TTL에는 만료가 설정된 키, 만료 설정이 없는 키, 존재하지 않는 키가 대응한다. 모두 새 버전의 반환 의미를 확인하기 위한 입력이다.
2 RC 문서에는 비동기 Future와 TLS 설정 등 다른 호환성 변경도 들어 있다. 이번 반환 타입 수정만 반영했다고 전체 마이그레이션이 끝난 것은 아니다. 사용하는 기능에 해당하는 항목을 추가로 대조해야 한다.
핵심은 누락을 오류로만 처리하던 코드를 다시 보는 데 있다. 서버가 돌려주는 “없음”을 타입에 보존하고, 앱이 그 상태에 어떻게 반응할지를 정하면 후보 버전의 변화가 필요한 코드 수정으로 이어진다.