Skip to content

About

Talk to Redis from the Scarlet programming language.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

31 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Redis Client

Talk to Redis from the Scarlet programming language, with a typed result for every one of its 275 commands.

Documentation • Redis commands


git submodule add https://github.com/scarletindustries/redis_client lib/redis

Keep hyphens out of the directory name, because Scarlet reads a hyphen in an import path as a minus sign. The client speaks RESP3, so it needs Redis 6 or newer.

Get and set

import scarlet/result
import ./lib/redis/redis.{Conn}
import ./lib/redis/strings

fn greet(c Conn) Result(Nil, redis.RedisError) {
	_ <- result.then(strings.set(c, 'greeting', 'hello'))
	value <- result.then(strings.get(c, 'greeting'))
	println(value or '(nil)')
	Ok(Nil)
}

redis.with_conn('127.0.0.1', 6379, greet)

with_conn closes the connection however the block ends, and each <- line stops at the first command that fails. A missing key is None, and a refused command is an Err that leaves the connection usable.

A hosted Redis usually comes as a URL, which with_conn_url takes directly. rediss:// is TLS, and a trailing /2 selects database 2:

redis.with_conn_url('rediss://default:s3cret@cache.example.com:6380/2', greet)

Pools

A plain connection belongs to the process that opened it. When many processes need Redis, start a pool. A pool is also a Conn, so every command works on it unchanged, and it costs nothing to hand to other processes:

import ./lib/redis/pool

pool.with_pool('127.0.0.1', 6379, 4, greet)

Two commands on a pool may land on two connections, so wrap a WATCH or MULTI in pool.with_conn to keep them on one. Subscribing needs a connection of its own and fails on a pool.

Pipelines

redis.pipeline sends a batch in one round trip and returns one result per command, in order. Against a local server, 500 SETs took 152ms one at a time and 6ms pipelined.

replies <- result.then(redis.pipeline(c, [
	['SET', 'hits', '0'],
	['INCR', 'hits'],
	['GET', 'hits'],
]))

transactions.transaction does the same inside MULTI and EXEC.

Everything else

The commands live in modules named the way Redis groups them: strings, keys, hashes, lists, sets, sorted_sets, streams, pubsub, geo, bitmaps, hyperloglog, arrays, transactions, scripting, connection, server and cluster. For anything not wrapped, send it yourself:

redis.command(c, ['OBJECT', 'ENCODING', 'user:1'])

Development

docker compose up -d          # redis on :5379
scripts/test                  # suite + pool; non-zero if a check fails
scarlet run example/tour.scrl
scarlet run example/pool.scrl

The TLS tests mint their own certificates and run against a second Redis behind a compose profile:

./scripts/tls-certs.sh                                    # once, mints test/tls/
docker compose --profile tls up -d                        # redis TLS on :6380
SSL_CERT_FILE=test/tls/ca.crt scarlet run test/tls.scrl
scarlet run test/tls.scrl                                 # the untrusted-issuer refusal
scripts/tls-records                                       # one-record pipeline, no Redis

Never point the TLS tests at the plaintext port. Redis never answers the handshake there, and it hangs for ever.

About

Talk to Redis from the Scarlet programming language.

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages