Redis
(kaappi redis) — Redis client with strings, lists, hashes, sets, sorted
sets, pub/sub, and pipelining.
thottam install kaappi-redis
Depends on kaappi-net (auto-installed). Uses the RESP2 protocol
(pure Scheme, no C dependencies beyond kaappi-net).
Quick start
(import (kaappi redis))
(define conn (redis-connect "127.0.0.1" 6379))
(redis-set conn "greeting" "hello!")
(redis-get conn "greeting") ;=> "hello!"
(redis-disconnect! conn)
Connection
(redis-connect host port) ;; connect
(redis-connect host port password) ;; connect with AUTH
(redis-disconnect! conn) ;; close
(redis-connected? conn) ;; check connection
(redis-ping conn) ;=> "PONG"
String commands
(redis-set conn "key" "value") ;=> "OK"
(redis-get conn "key") ;=> "value" or #f if missing
(redis-del conn "key" ...) ;=> number deleted
(redis-exists conn "key") ;=> #t or #f
(redis-incr conn "counter") ;=> new value (integer)
(redis-decr conn "counter") ;=> new value (integer)
(redis-expire conn "key" 60) ;=> #t if timeout was set
(redis-ttl conn "key") ;=> seconds remaining, -1 if no expiry
(redis-keys conn "user:*") ;=> list of matching keys
(redis-mset conn "a" "1" "b" "2") ;=> "OK"
(redis-mget conn "a" "b") ;=> ("1" "2")
(redis-setnx conn "key" "value") ;=> #t if key was set (didn't exist)
(redis-setex conn "key" 60 "value") ;=> "OK" (set with TTL in seconds)
(redis-append conn "key" " world") ;=> new string length
(redis-strlen conn "key") ;=> string length
List commands
(redis-lpush conn "list" "a" "b" "c") ;=> list length
(redis-rpush conn "list" "x" "y") ;=> list length
(redis-lpop conn "list") ;=> value or #f
(redis-rpop conn "list") ;=> value or #f
(redis-lrange conn "list" 0 -1) ;=> all elements
(redis-llen conn "list") ;=> length
(redis-lindex conn "list" 0) ;=> element at index
(redis-lset conn "list" 0 "new") ;=> "OK"
Hash commands
(redis-hset conn "hash" "field" "val") ;=> 1 (new field) or 0 (updated)
(redis-hget conn "hash" "field") ;=> "val" or #f
(redis-hdel conn "hash" "field") ;=> number deleted
(redis-hgetall conn "hash") ;=> (("f1" . "v1") ("f2" . "v2"))
(redis-hexists conn "hash" "field") ;=> #t or #f
(redis-hkeys conn "hash") ;=> list of field names
(redis-hvals conn "hash") ;=> list of values
(redis-hlen conn "hash") ;=> number of fields
Set commands
(redis-sadd conn "set" "a" "b" "c") ;=> number added
(redis-srem conn "set" "a") ;=> number removed
(redis-smembers conn "set") ;=> list of members
(redis-sismember conn "set" "a") ;=> #t or #f
(redis-scard conn "set") ;=> cardinality
Sorted set commands
(redis-zadd conn "zset" 1.0 "a") ;=> 1
(redis-zrem conn "zset" "a") ;=> number removed
(redis-zrange conn "zset" 0 -1) ;=> list ordered by score
(redis-zscore conn "zset" "a") ;=> score as string
(redis-zcard conn "zset") ;=> cardinality
(redis-zrank conn "zset" "a") ;=> 0-based rank
Pub/Sub
;; Publish
(redis-publish conn "channel" "message") ;=> number of receivers
;; Subscribe (blocking)
(redis-subscribe conn "channel"
(lambda (channel message)
(display message) (newline)
#t)) ;; return #f to unsubscribe
The subscribe callback receives each message. Return #t to keep
listening, #f to unsubscribe and return.
Pipelining
Send multiple commands at once to reduce round trips:
(redis-pipeline conn
'("SET" "a" "1")
'("SET" "b" "2")
'("GET" "a")
'("GET" "b"))
;=> ("OK" "OK" "1" "2")
Pipelining sends all commands before reading any replies. This is much
faster than individual commands when you have many operations.
Generic command
For Redis commands not covered by convenience functions:
(redis-command conn "INFO" "server")
(redis-command conn "FLUSHDB")
(redis-command conn "SELECT" "1")
(redis-command conn "TYPE" "mykey")
Reply mapping
| Redis reply |
Scheme value |
Simple string (+OK) |
"OK" |
| Bulk string |
string |
| Null bulk string |
#f |
| Integer |
exact integer |
| Array |
list |
| Error |
raises Scheme error |
Common patterns
Caching with expiry
(define (cache-get conn key)
(redis-get conn key))
(define (cache-set conn key value ttl-seconds)
(redis-setex conn key ttl-seconds value))
(define (cache-or-compute conn key ttl compute)
(or (cache-get conn key)
(let ((val (compute)))
(cache-set conn key val ttl)
val)))
Rate limiting
(define (rate-limited? conn client-id max-requests window-seconds)
(let ((key (string-append "rate:" client-id)))
(let ((count (redis-incr conn key)))
(when (= count 1)
(redis-expire conn key window-seconds))
(> count max-requests))))
Job queue
;; Producer
(define (enqueue conn queue job-data)
(redis-rpush conn queue (json-write-string job-data)))
;; Consumer
(define (dequeue conn queue)
(let ((data (redis-lpop conn queue)))
(if data (json-read-string data) #f)))
Session store
(define (session-save conn session-id data ttl)
(redis-setex conn
(string-append "session:" session-id)
ttl
(json-write-string data)))
(define (session-load conn session-id)
(let ((data (redis-get conn (string-append "session:" session-id))))
(if data (json-read-string data) #f)))
API reference
Connection
| Procedure |
Description |
(redis-connect host port [password]) |
Connect to Redis |
(redis-disconnect! conn) |
Close connection |
(redis-connected? conn) |
Check connection |
(redis-ping conn) |
Ping server |
Strings
| Procedure |
Description |
(redis-get conn key) |
Get value |
(redis-set conn key value) |
Set value |
(redis-del conn key ...) |
Delete keys |
(redis-exists conn key) |
Check existence |
(redis-incr conn key) |
Increment |
(redis-decr conn key) |
Decrement |
(redis-expire conn key seconds) |
Set TTL |
(redis-ttl conn key) |
Get TTL |
(redis-keys conn pattern) |
Find keys |
(redis-mset conn k v ...) |
Set multiple |
(redis-mget conn k ...) |
Get multiple |
(redis-setnx conn key value) |
Set if not exists |
(redis-setex conn key seconds value) |
Set with TTL |
(redis-append conn key value) |
Append to string |
(redis-strlen conn key) |
String length |
Lists
| Procedure |
Description |
(redis-lpush conn key val ...) |
Push to head |
(redis-rpush conn key val ...) |
Push to tail |
(redis-lpop conn key) |
Pop from head |
(redis-rpop conn key) |
Pop from tail |
(redis-lrange conn key start stop) |
Get range |
(redis-llen conn key) |
List length |
(redis-lindex conn key index) |
Get by index |
(redis-lset conn key index value) |
Set by index |
Hashes
| Procedure |
Description |
(redis-hset conn key field value) |
Set field |
(redis-hget conn key field) |
Get field |
(redis-hdel conn key field) |
Delete field |
(redis-hgetall conn key) |
Get all as alist |
(redis-hexists conn key field) |
Check field |
(redis-hkeys conn key) |
All field names |
(redis-hvals conn key) |
All values |
(redis-hlen conn key) |
Field count |
Sets
| Procedure |
Description |
(redis-sadd conn key val ...) |
Add members |
(redis-srem conn key val) |
Remove member |
(redis-smembers conn key) |
All members |
(redis-sismember conn key val) |
Check membership |
(redis-scard conn key) |
Cardinality |
Sorted sets
| Procedure |
Description |
(redis-zadd conn key score val) |
Add with score |
(redis-zrem conn key val) |
Remove |
(redis-zrange conn key start stop) |
Range by rank |
(redis-zscore conn key val) |
Get score |
(redis-zcard conn key) |
Cardinality |
(redis-zrank conn key val) |
Get rank |
Pub/Sub and pipeline
| Procedure |
Description |
(redis-publish conn channel message) |
Publish |
(redis-subscribe conn channel callback) |
Subscribe (blocking) |
(redis-pipeline conn cmd ...) |
Pipeline commands |
(redis-command conn cmd arg ...) |
Generic command |