This is the main module for managing in-process replicas of Redis/Valkey data.
This module provides a simple interface for starting/stopping/inspecting replica instances, as well as commands for accessing the replicated data.
Veidrodelis instance is a single GenServer process that connects to Redis/Valkey, fetches the data via replication protocol and builds an in-memory projection of the data.
The process is registered under global id which is used for reading the replicated data without calls to the replicating GenServer.
Sample Usage
# Start a Veidrodelis instance
{:ok, pid} = Veidrodelis.start_link(
id: :my_instance,
host: "localhost",
port: 6379
)
# Query data using accessor functions
{:ok, value} = Veidrodelis.get(:my_instance, 0, "mykey")
{:ok, len} = Veidrodelis.llen(:my_instance, 0, "mylist")
# Read ransacitons
{:ok, [{:ok, debit}, {:ok, credit}]} = Veidrodelis.read_tx(:my_instance, 0, [
{:get, "account:123:debit"},
{:get, "account:123:credit"}
])
# Read transactions via Lua script
{:ok, [debit, credit]} = Veidrodelis.read_tx(
:my_instance,
0,
"return {ts.get('account:123:debit'), ts.get('account:123:credit')}"
)
# Stop the instance
:ok = Veidrodelis.stop(pid)
Summary
Functions
Gets the value of a string key.
Gets the host and port of the currently connected Redis server.
Gets the current replication state of a Veidrodelis instance.
Returns true if field exists in the hash stored at key.
Returns up to count lexicographically first field/value pairs in the hash stored at key.
Returns the value associated with field in the hash stored at key.
Returns all fields and values of the hash stored at key.
Returns all field names in the hash stored at key.
Returns up to count lexicographically last field/value pairs in reverse order.
Returns the number of fields in the hash stored at key.
Returns the values associated with the specified fields in the hash stored at key.
Returns up to count field/value pairs after field in the hash stored at key.
Returns up to count field/value pairs before field in the hash stored at key.
Returns up to count random fields (and optional values) from the hash stored at key.
Returns the length of the value stored at field (string length).
Returns all values in the hash stored at key.
Returns the length of the list stored at key.
Returns the specified elements of the list stored at key.
Compiles a Lua script to bytecode for faster execution.
Executes multiple read-only commands or a Lua script atomically.
Returns the cardinality (number of elements) of the set stored at key.
Returns the difference of the provided sets (first key minus remaining keys).
Gets up to count members from the beginning of a set.
Returns the intersection of the provided sets.
Returns the cardinality of the intersection of the provided sets.
Returns whether member is a member of the set stored at key.
Gets up to count members from the end of a set in reverse order.
Returns all members of the set stored at key.
Returns membership status for each member in the provided list.
Gets up to count members after the given member in a set.
Gets up to count members before the given member in a set.
Returns up to count random members from the set stored at key.
Starts a Veidrodelis instance that connects to Redis and processes replication stream.
Stops a Veidrodelis instance.
Returns the union of the provided sets.
Unsubscribes from updates for a specific key.
Subscribes to updates for a specific key in a database.
Returns the cardinality (number of elements) of the sorted set stored at key.
Returns up to count member/score pairs from the start of the sorted set.
Returns up to count member/score pairs from the end of the sorted set in reverse order.
Returns up to count member/score pairs after member in the sorted set.
Returns up to count member/score pairs before member in the sorted set.
Returns the specified range of elements in the sorted set stored at key.
Returns all members in the sorted set stored at key with scores between min and max (inclusive).
Returns the rank (0-based index) where the member would be in the sorted set,
ordered from lowest to highest score. Returns nil if the member or key doesn't exist.
Returns the rank (0-based index) where the member would be in the sorted set,
ordered from highest to lowest score. Returns nil if the member or key doesn't exist.
Returns the score of member in the sorted set stored at key.
Types
Functions
@spec get(instance_id(), db(), key()) :: {:ok, binary() | nil} | {:error, term()}
Gets the value of a string key.
@spec get_connected_to(pid() | instance_id()) :: {:ok, {String.t(), non_neg_integer()}} | {:error, :not_connected}
Gets the host and port of the currently connected Redis server.
Returns the actual host and port that the Veidrodelis instance is connected to. For sentinel-based connections, this returns the discovered server address. For direct connections, this returns the configured host and port.
Parameters
pid_or_id- Either the Replica GenServer PID or the Veidrodelis instance ID
Returns
{:ok, {host, port}}- The connected host (string) and port (integer){:error, :not_connected}- Replica is not currently connected
Examples
# Using instance ID
{:ok, {host, port}} = Veidrodelis.get_connected_to(:my_instance)
# Using PID directly
{:ok, pid} = Veidrodelis.start_link(id: :test, host: "localhost", port: 6379)
{:ok, {host, port}} = Veidrodelis.get_connected_to(pid)
@spec get_replication_state(pid() | instance_id()) :: Vdr.RedisStream.Replica.replica_state()
Gets the current replication state of a Veidrodelis instance.
Returns true if field exists in the hash stored at key.
@spec hfirst(instance_id(), db(), key(), non_neg_integer()) :: {:ok, [{hash_key(), binary()}]} | {:error, term()}
Returns up to count lexicographically first field/value pairs in the hash stored at key.
Returns the value associated with field in the hash stored at key.
Returns all fields and values of the hash stored at key.
@spec hkeys(instance_id(), db(), key()) :: {:ok, [hash_key()]} | {:error, term()}
Returns all field names in the hash stored at key.
@spec hlast(instance_id(), db(), key(), non_neg_integer()) :: {:ok, [{hash_key(), binary()}]} | {:error, term()}
Returns up to count lexicographically last field/value pairs in reverse order.
@spec hlen(instance_id(), db(), key()) :: {:ok, non_neg_integer()} | {:error, term()}
Returns the number of fields in the hash stored at key.
Returns the values associated with the specified fields in the hash stored at key.
@spec hnext(instance_id(), db(), key(), binary(), non_neg_integer()) :: {:ok, [{hash_key(), binary()}]} | {:error, term()}
Returns up to count field/value pairs after field in the hash stored at key.
@spec hprev(instance_id(), db(), key(), binary(), non_neg_integer()) :: {:ok, [{hash_key(), binary()}]} | {:error, term()}
Returns up to count field/value pairs before field in the hash stored at key.
@spec hrandfield(instance_id(), db(), key(), integer(), boolean()) :: {:ok, [{hash_key(), binary()} | binary()]} | {:error, term()}
Returns up to count random fields (and optional values) from the hash stored at key.
@spec hstrlen(instance_id(), db(), key(), hash_key()) :: {:ok, non_neg_integer()} | {:error, term()}
Returns the length of the value stored at field (string length).
@spec hvals(instance_id(), db(), key()) :: {:ok, [binary()]} | {:error, term()}
Returns all values in the hash stored at key.
@spec llen(instance_id(), db(), key()) :: {:ok, non_neg_integer()} | {:error, term()}
Returns the length of the list stored at key.
@spec lrange(instance_id(), db(), key(), integer(), integer()) :: {:ok, [binary()]} | {:error, term()}
Returns the specified elements of the list stored at key.
@spec lua_load(instance_id(), lua_script()) :: {:ok, lua_compiled_script()} | {:error, term()}
Compiles a Lua script to bytecode for faster execution.
The compiled bytecode can be passed to read_tx/3 instead of a script string.
This is useful when the same script will be executed multiple times.
Examples
{:ok, pid} = Veidrodelis.start_link(id: :my_instance)
script = "return ts.get('key1')"
{:ok, bytecode} = Veidrodelis.lua_load(:my_instance, script)
{:ok, result} = Veidrodelis.read_tx(:my_instance, 0, bytecode)
@spec read_tx(instance_id(), db(), [command()] | lua_script() | lua_compiled_script()) :: {:ok, term() | [ok: term(), error: term()]} | {:error, term()}
Executes multiple read-only commands or a Lua script atomically.
With a list of commands
Executes multiple read commands atomically. Commands are executed in order and their results are returned as a list of tuples.
Supported Commands
{:get, key}- Get string value{:hget, key, field}- Get hash field value{:hmget, key, fields}- Get multiple hash field values{:hgetall, key}- Get all hash fields and values{:hkeys, key}- Get hash field names{:hvals, key}- Get hash values{:hlen, key}- Get hash length{:hexists, key, field}- Check hash field existence{:hstrlen, key, field}- Get hash field length{:hrandfield, key, count, with_values}- Random hash field(s){:hfirst, key, count}- Get up tocountfield/value pairs from the beginning{:hlast, key, count}- Get up tocountfield/value pairs from the end{:hnext, key, field, count}- Get up tocountfield/value pairs afterfield{:hprev, key, field, count}- Get up tocountfield/value pairs beforefield{:llen, key}- Get list length{:lrange, key, start, stop}- Get list range{:smembers, key}- Get set members{:sismember, key, member}- Check set membership{:scard, key}- Get set cardinality{:smismember, key, members}- Check membership of multiple members{:srandmember, key, count}- Get random members{:sunion, keys}- Union of sets{:sinter, keys}- Intersection of sets{:sdiff, keys}- Difference of sets{:sintercard, keys}- Cardinality of intersection{:sfirst, key, count}- Get up tocountmembers from the beginning{:slast, key, count}- Get up tocountmembers from the end{:snext, key, member, count}- Get up tocountmembers immediately aftermember{:sprev, key, member, count}- Get up tocountmembers immediately beforemember{:zscore, key, member}- Get sorted set member score{:zcard, key}- Get sorted set cardinality{:zrange, key, start, stop, with_scores}- Get sorted set range{:zrangebyscore, key, min, max, with_scores}- Get sorted set range by score{:zrank, key, member}- Get sorted set member rank{:zrevrank, key, member}- Get sorted set member reverse rank{:zcount, key, min, max}- Count sorted set members in score range{:zfirst, key, count}- Get up tocountmember/score pairs from the beginning{:zlast, key, count}- Get up tocountmember/score pairs from the end{:znext, key, member, count}- Get up tocountmember/score pairs aftermember{:zprev, key, member, count}- Get up tocountmember/score pairs beforemember
Example
{:ok, [value1, value2]} = Veidrodelis.read_tx(:my_instance, 0, [
{:get, "key1"},
{:hget, "hash1", "field1"}
])With a Lua script
Executes a Lua script atomically under the storage mutex. The script has access to:
ts.get(key)- Get a string valuets.hget(key, field)- Get a hash field valuets.llen(key)- Get list lengthts.lrange(key, start, stop)- Get list rangets.smembers(key)- Get set membersts.sismember(key, member)- Check set membershipts.scard(key)- Get set cardinalityts.smismember(key, members)- Check multiple membersts.srandmember(key, count)- Get random membersts.sunion(keys)- Union of setsts.sinter(keys)- Intersection of setsts.sdiff(keys)- Difference of setsts.sintercard(keys)- Intersection cardinalityts.sfirst(key, count)- Get first set membersts.slast(key, count)- Get last set membersts.snext(key, member, count)- Get next set membersts.sprev(key, member, count)- Get previous set membersts.hgetall(key)- Get all hash fields and valuests.hmget(key, fields)- Get multiple hash field valuests.hkeys(key)- Get hash field namests.hvals(key)- Get hash valuests.hlen(key)- Get hash lengthts.hexists(key, field)- Check if hash field existsts.hstrlen(key, field)- Get hash field lengthts.hrandfield(key, count, with_values)- Get random hash fieldsts.hfirst(key, count)- Get first hash field/value pairsts.hlast(key, count)- Get last hash field/value pairsts.hnext(key, field, count)- Get next hash fields after given fieldts.hprev(key, field, count)- Get previous hash fields before given fieldts.zscore(key, member)- Get sorted set member scorets.zcard(key)- Get sorted set cardinalityts.zrange(key, start, stop)- Get sorted set rangets.zrangebyscore(key, min, max)- Get sorted set range by scorets.zrank(key, member)- Get sorted set member rankts.zrevrank(key, member)- Get sorted set member reverse rankts.zcount(key, min, max)- Count sorted set members in score rangets.zfirst(key, count)- Get first sorted set membersts.zlast(key, count)- Get last sorted set membersts.znext(key, member, count)- Get next sorted set membersts.zprev(key, member, count)- Get previous sorted set members
Example
{:ok, pid} = Veidrodelis.start_link(id: :my_instance)
script = "return ts.get('key1')"
{:ok, result} = Veidrodelis.read_tx(:my_instance, 0, script)Returns
{:ok, results}- For commands: list of results. For scripts: the script's return value{:error, reason}- Execution error
@spec scard(instance_id(), db(), key()) :: {:ok, non_neg_integer()} | {:error, term()}
Returns the cardinality (number of elements) of the set stored at key.
@spec sdiff(instance_id(), db(), [key()]) :: {:ok, [binary()]} | {:error, term()}
Returns the difference of the provided sets (first key minus remaining keys).
@spec sfirst(instance_id(), db(), key(), non_neg_integer()) :: {:ok, [binary()]} | {:error, term()}
Gets up to count members from the beginning of a set.
@spec sinter(instance_id(), db(), [key()]) :: {:ok, [binary()]} | {:error, term()}
Returns the intersection of the provided sets.
@spec sintercard(instance_id(), db(), [key()]) :: {:ok, non_neg_integer()} | {:error, term()}
Returns the cardinality of the intersection of the provided sets.
Returns whether member is a member of the set stored at key.
@spec slast(instance_id(), db(), key(), non_neg_integer()) :: {:ok, [binary()]} | {:error, term()}
Gets up to count members from the end of a set in reverse order.
@spec smembers(instance_id(), db(), key()) :: {:ok, [binary()]} | {:error, term()}
Returns all members of the set stored at key.
Returns membership status for each member in the provided list.
@spec snext(instance_id(), db(), key(), binary(), non_neg_integer()) :: {:ok, [binary()]} | {:error, term()}
Gets up to count members after the given member in a set.
@spec sprev(instance_id(), db(), key(), binary(), non_neg_integer()) :: {:ok, [binary()]} | {:error, term()}
Gets up to count members before the given member in a set.
Returns up to count random members from the set stored at key.
Starts a Veidrodelis instance that connects to Redis and processes replication stream.
Options
:id- Veidrodelis instance ID, required:host- Redis host (default: "localhost"). Cannot be used with:sentinel.:port- Redis port (default: 6379). Cannot be used with:sentinel.:sentinel- Sentinel configuration (keyword list). Cannot be used with:host/:port.:sentinels- List of sentinel nodes (required), each with:hostand:port:group- Name of the primary group in sentinel (required):role- Server role to discover::primaryor:replica(default::primary):connect_opts- Redix connection options for sentinel connections (optional):replica_connect_opts- Redix connection options for discovered Redis server (optional)
:username- Redis username for ACL authentication (default: nil). Only for direct connections.:password- Redis password (default: nil). Only for direct connections.:ssl- Use SSL/TLS (default: false). Only for direct connections.:ssl_opts- SSL options (default: []). Only for direct connections.:reconnect- Enable automatic reconnection (default: true):reconnect_delay_ms- Initial delay before reconnection in ms (default: 1000):max_reconnect_delay_ms- Maximum delay between reconnection attempts in ms (default: 30000)
For full documentation of sentinel options and advanced features, see Vdr.RedisStream.Replica.
Returns
{:ok, pid}- Successfully started (returns Replica GenServer PID){:error, reason}- Failed to start
Examples
Direct Connection
opts = [
id: :my_instance,
host: "localhost",
port: 6379
]
{:ok, pid} = Veidrodelis.start_link(opts)Sentinel Connection
opts = [
id: :my_instance,
sentinel: [
sentinels: [
[host: "sentinel1", port: 26379],
[host: "sentinel2", port: 26379]
],
group: "myprimary",
role: :primary,
# Optional: Connection options for sentinel
connect_opts: [timeout: 1000],
# Optional: Connection options for Redis server
replica_connect_opts: [password: "redis_password", ssl: true]
]
]
{:ok, pid} = Veidrodelis.start_link(opts)
@spec stop(pid()) :: :ok
Stops a Veidrodelis instance.
@spec sunion(instance_id(), db(), [key()]) :: {:ok, [binary()]} | {:error, term()}
Returns the union of the provided sets.
Unsubscribes from updates for a specific key.
Parameters
id- Veidrodelis instance IDdb- Database numberkey- The key to unwatch (binary)timeout- The timeout for the call (default: 5000ms)
Returns
:ok- Successfully unsubscribed{:error, :not_found}- Instance or watch not found
Example
# Unsubscribe from key updates
:ok = Veidrodelis.unwatch(:my_instance, 0, "user:123")
Subscribes to updates for a specific key in a database.
When the key is modified, the calling process will receive a message:
{ref, %Vdr.WatchEvent.Update{command: cmd, db: db}}
When the replica transitions to streaming mode after an RDB transfer, the calling
process will receive: {ref, %Vdr.WatchEvent.Init{}}
Parameters
id- Veidrodelis instance IDdb- Database numberkey- The key to watch (binary)ref- Reference value to identify this watch in notificationstimeout- The timeout for the call (default: 5000ms)
Returns
:ok- Successfully subscribed{:error, :not_found}- Instance not found{:error, :already_registered}- This process is already watching this key
Example
# Subscribe to key updates
:ok = Veidrodelis.watch(:my_instance, 0, "user:123", :my_watch_ref)
# Receive notifications
receive do
{:my_watch_ref, %Vdr.WatchEvent.Update{command: cmd, db: db}} ->
IO.inspect({:update, cmd, db})
{:my_watch_ref, %Vdr.WatchEvent.Init{}} ->
IO.puts("Streaming mode started")
end
@spec zcard(instance_id(), db(), key()) :: {:ok, non_neg_integer()} | {:error, term()}
Returns the cardinality (number of elements) of the sorted set stored at key.
@spec zfirst(instance_id(), db(), key(), non_neg_integer()) :: {:ok, [{score(), binary()}]} | {:error, term()}
Returns up to count member/score pairs from the start of the sorted set.
@spec zlast(instance_id(), db(), key(), non_neg_integer()) :: {:ok, [{score(), binary()}]} | {:error, term()}
Returns up to count member/score pairs from the end of the sorted set in reverse order.
@spec znext(instance_id(), db(), key(), binary(), non_neg_integer()) :: {:ok, [{score(), binary()}]} | {:error, term()}
Returns up to count member/score pairs after member in the sorted set.
@spec zprev(instance_id(), db(), key(), binary(), non_neg_integer()) :: {:ok, [{score(), binary()}]} | {:error, term()}
Returns up to count member/score pairs before member in the sorted set.
@spec zrange(instance_id(), db(), key(), integer(), integer(), boolean()) :: {:ok, [{binary(), score()}] | [binary()]} | {:error, term()}
Returns the specified range of elements in the sorted set stored at key.
If with_scores is true, returns a list of {member, score} tuples.
If with_scores is false, returns a list of members only.
@spec zrangebyscore(instance_id(), db(), key(), score(), score(), boolean()) :: {:ok, [{binary(), score()}] | [binary()]} | {:error, term()}
Returns all members in the sorted set stored at key with scores between min and max (inclusive).
If with_scores is true, returns a list of {member, score} tuples.
If with_scores is false, returns a list of members only.
Examples
{:ok, pid} = Veidrodelis.start_link(id: :my_instance)
{:ok, members} = Veidrodelis.zrangebyscore(:my_instance, 0, "myzset", 1.0, 3.0, true)
# Returns: [{"one", 1.0}, {"two", 2.0}, {"three", 3.0}]
{:ok, members} = Veidrodelis.zrangebyscore(:my_instance, 0, "myzset", 1.0, 3.0, false)
# Returns: ["one", "two", "three"]
@spec zrank(instance_id(), db(), key(), binary()) :: {:ok, non_neg_integer() | nil} | {:error, term()}
Returns the rank (0-based index) where the member would be in the sorted set,
ordered from lowest to highest score. Returns nil if the member or key doesn't exist.
@spec zrevrank(instance_id(), db(), key(), binary()) :: {:ok, non_neg_integer() | nil} | {:error, term()}
Returns the rank (0-based index) where the member would be in the sorted set,
ordered from highest to lowest score. Returns nil if the member or key doesn't exist.
Returns the score of member in the sorted set stored at key.