HORIZON HASKELLDocslts/ghc-9.14.x3e2d5682026-10-11Search names, modules, packages, or :: a typeCtrl K

GHC 9.14.1 · lts/ghc-9.14.x · 3e2d568 · 2026-10-11

Modulehedis-0.16.4Haskell2010

Database.Redis

  • 17 types
  • 4 classes
  • 16 values
  • Packagehedis-0.16.4
  • Exports37
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceConnection.hs

How To Use This Package

0 declarations

Simplest usage of this package is to connect to a Redis server and run commands against it and close connection when done:

Connect to a Redis server:

let Right ci = parseConnectInfo "redis://localhost:6379"
conn <- checkedConnect ci

connect or checkedConnect creates a connection pool under the hood. This poll manages reuse of the connections connection livetimes, and connection restore in the case of the connection loss.

Send commands to the server:

{-# LANGUAGE OverloadedStrings #-}
...
runRedis conn $ do
  set "hello" "hello"
  set "world" "world"
  hello <- get "hello"
  world <- get "world"
  liftIO $ print (hello,world)

disconnect all idle resources in the connection pool, and destroy the pool:

disconnect conn

Managing connections

Redis connections are managed by a connection pool enclosed in the Connection type, that keeps all required state.

datadata Connection
#

A threadsafe pool of network connections to a Redis server. Use the connect function to create one.

To create a connection one need to contruct a ConnectInfo record. The easiest way to do this is to use the parseConnectInfo function, which takes a URL and returns a ConnectInfo record.

datadata ConnectInfo
#

Information for connnecting to a Redis server.

It is recommended to not use the ConnInfo data constructor directly. Instead use defaultConnectInfo and update it with record syntax. For example to connect to a password protected Redis server running on localhost and listening to the default port:

myConnectInfo :: ConnectInfo
myConnectInfo = defaultConnectInfo {connectAuth = Just "secret"}

Or better yet, use parseConnectInfo to parse a URL.

Constructors

Instances1Show

Default information for connecting:

 connectAddr           = ConnectAddrHostPort "localhost" 6379 -- Redis default port
 connectAuth           = Nothing         -- No password
 connectUsername       = Nothing         -- No user
 connectDatabase       = 0               -- SELECT database 0
 connectMaxConnections = 50              -- Up to 50 connections
 connectNumStripes     = Just 1          -- A single stripe
 connectMaxIdleTime    = 30              -- Keep open for 30 seconds
 connectTimeout        = Nothing         -- Don't add timeout logic
 connectTLSParams      = Nothing         -- Do not use TLS
 connectHooks          = defaultHooks    -- Do nothing
 connectPoolLabel      = ""              -- no label

Parse a ConnectInfo from a URL according to the Rules in Redis client

Standalone Redis:

redis :// [[username :] password@] host [:port][/database]
Example1 expression
parseConnectInfo "redis://username:password@host:42/2"Right (ConnInfo {connectAddr = ConnectAddrHostPort "host" 42, connectAuth = Just "password", connectUsername = Just "username", connectDatabase = 2, connectMaxConnections = 50, connectNumStripes = Just 1, connectMaxIdleTime = 30s, connectTimeout = Nothing, connectTLSParams = Nothing, connectHooks = Hooks {...}, connectPoolLabel = ""})
Example1 expression
parseConnectInfo "redis://password@host:42/2"Right (ConnInfo {connectAddr = ConnectAddrHostPort "host" 42, connectAuth = Just "password", connectUsername = Nothing, connectDatabase = 2, connectMaxConnections = 50, connectNumStripes = Just 1, connectMaxIdleTime = 30s, connectTimeout = Nothing, connectTLSParams = Nothing, connectHooks = Hooks {...}, connectPoolLabel = ""})

TLS-enabled Redis:

rediss :// [[username :] password@] host [: port][/database]

Unix socket Redis:

redis-socket :// [[username :] password@]path [? [&database=database]
Example1 expression
parseConnectInfo "redis-socket://password@/tmp/redis.sock?database=2"Right (ConnInfo {connectAddr = ConnectAddrUnixSocket "/tmp/redis.sock", connectAuth = Just "password", connectUsername = Nothing, connectDatabase = 2, connectMaxConnections = 50, connectNumStripes = Just 1, connectMaxIdleTime = 30s, connectTimeout = Nothing, connectTLSParams = Nothing, connectHooks = Hooks {...}, connectPoolLabel = ""})
Example1 expression
parseConnectInfo "redis://username:password@host:42/db"Left "Invalid port: db"

The scheme is validated, to prevent mixing up configurations:

Example1 expression
parseConnectInfo "postgres://"Left "Wrong scheme postgres:"

Beyond that, all values are optional. Omitted values are taken from defaultConnectInfo:

Example1 expression
parseConnectInfo "rediss://"Right (ConnInfo {connectAddr = ConnectAddrHostPort "localhost" 6379, connectAuth = Nothing, connectUsername = Nothing, connectDatabase = 0, connectMaxConnections = 50, connectNumStripes = Just 1, connectMaxIdleTime = 30s, connectTimeout = Nothing, connectTLSParams = Just (ClientParams ...), connectHooks = Hooks {...}, connectPoolLabel = ""})
valuedisconnect :: Connection -> IO ()
#

Destroy all idle resources in the pool, works for all types of the connection.

Single node

If you are connecting to a single Redis node, use the connect or checkedConnect functions.

Clustered

If you are connecting to a Redis cluster, use the connectCluster or checkedConnectCluster functions.

At this point, some functions are not supported in the cluster mode:

  • CONFIG

  • AUTH

  • SCAN

  • MOVE, SELECT

  • RESET

Sentinel

If you are connecting to a Redis sentinel, use functions from the Database.Redis.Sentinel module, such as connect or Database.Redis.Sentinel.checkedConnectSentinel.

Those functions live in a separate module to simplify move from the Single-node to Sentinel mode.

Running Commands

Redis commands behave differently when issued in- or outside of a transaction. To make them work in both contexts, most command functions have a type signature similar to the following:

echo :: (RedisCtx m f) => ByteString -> m (f ByteString)

Here is how to interpret this type signature:

  • The argument types are independent of the execution context. echo always takes a ByteString parameter, whether in- or outside of a transaction. This is true for all command functions.

  • All Redis commands return their result wrapped in some "container". The type f of this container depends on the commands execution context m. The ByteString return type in the example is specific to the echo command. For other commands, it will often be another type.

  • In the "normal" context Redis, outside of any transactions, results are wrapped in an Either Reply.

  • Inside a transaction, in the RedisTx context, results are wrapped in a Queued.

In short, you can view any command with a RedisCtx constraint in the type signature, to "have two types". For example echo "has both types":

echo :: ByteString -> Redis (Either Reply ByteString)
echo :: ByteString -> RedisTx (Queued ByteString)

To see all commands refer to the Database.Redis.Commands module:

It's important to understand several features that the library provides.

Automatic Pipelining

Commands are automatically pipelined as much as possible. For example, in the above "hello world" example, all four commands are pipelined. Automatic pipelining makes use of Haskell's laziness. As long as a previous reply is not evaluated, subsequent commands can be pipelined.

Automatic pipelining is limited to the scope of runRedis call and it is guaranteed that every reply expected as a part of runRedis execution gets received after runRedis invocation.

To keep memory usage low, the number of requests "in the pipeline" is limited (per connection) to 1000. After that number, the next command is sent only when at least one reply has been received. That means, command functions may block until there are less than 1000 outstanding replies.

This feature has several implications. Consider the following example:

runRedis conn $ do
  set "key1" "value1"
  _ <- get "nonexistingkey"
  set "key2" "value2"

Even the "nonexistingkey" does not exist and would return a error it does not prevent commands from execution, so both key1 and key2 will be updated.

To enforce verification of the reply one could wrap commands in ExceptT:

runRedis conn $ runExceptT $ do
  ExceptT $ set "key1" "value1"
  _ <- ExceptT $get "nonexistingkey"
  ExceptT $ set "key2" "value2"

But this code will break the pipelining and second command will be sent only after first command reply is received.

Error Behavior

Operations against keys holding the wrong kind of value:

Outside of a transaction, if the Redis server returns an

Error

, command functions will return

Left

the

Reply

. The library user can inspect the error message to gain information on what kind of error occured.

Connection to the server lost:

In case of a lost connection, command functions throw a

ConnectionLostException

. It can only be caught outside of

runRedis

.

Trying to connect to an unreachable server:

When trying to connect to a server that does not exist or can't be reached, the connection pool only starts the first connection when actually executing a call to the server. This can lead to discovering very late that the server is not available, for example when running a server that logs to Redis. To prevent this, run a

ping

command directly after connecting or use the

checkedConnect

function which encapsulates this behavior.

Exceptions:

Any exceptions can only be caught

outside

of

runRedis

. This way the connection pool can properly close the connection, making sure it is not left in an unusable state, e.g. closed or inside a transaction.

Transactions

hedis supports Redis transactions. See Database.Redis.Transactions for more information.

Pub/Sub

hedis supports Redis Pub/Sub. See Database.Redis.PubSub for more information.

Advanced Usage

0 declarations

The Redis Monad

newtypenewtype Redis a
#

Context for normal command execution, outside of transactions. Use runRedis to run actions of this type.

In this context, each result is wrapped in an Either to account for the possibility of Redis returning an Error reply.

Instances11Monad, Functor, MonadFail, Applicative, MonadIO, MonadCatch, …
valueunRedis :: Redis a -> ReaderT RedisEnv IO a
#

Deconstruct Redis constructor.

unRedis and reRedis can be used to define instances for arbitrary typeclasses.

WARNING! These functions are considered internal and no guarantee is given at this point that they will not break in future.

classclass MonadRedis m => RedisCtx (m :: Type -> Type) (f :: Type -> Type) | m -> f where
#

This class captures the following behaviour: In a context m, a command will return its result wrapped in a "container" of type f.

Please refer to the Command Type Signatures section of this page for more information.

Methods

Instances2RedisCtx

Lua Scripting

Lua values returned from the eval and evalsha functions will be converted to Haskell values by the decode function from the RedisResult type class.

 Lua Type      | Haskell Type       | Conversion Example
 --------------|--------------------|-----------------------------
 Number        | Integer            | 1.23   => 1
 String        | ByteString, Double | "1.23" => "1.23" or 1.23
 Boolean       | Bool               | false  => False
 Table         | List               | {1,2}  => [1,2]
 

Additionally, any of the Haskell types from the table above can be wrapped in a Maybe:

 42  => Just 42 :: Maybe Integer
 nil => Nothing :: Maybe Integer
 

Note that Redis imposes some limitations on the possible conversions:

  • Lua numbers can only be converted to Integers. Only Lua strings can be interpreted as Doubles.

  • Associative Lua tables can not be converted at all. Returned tables must be "arrays", i.e. indexed only by integers.

The Redis Scripting website (http://redis.io/commands/eval) documents the exact semantics of the scripting commands and value conversion.

Hooks

typetype SendHook = (ByteString -> IO ()) -> ByteString -> IO ()
#

A hook for sending raw bytes to the server.

This sits below request rendering and can be used to observe the exact wire payload sent on the socket.

Low-Level Command API

valuesendRequest :: (RedisCtx m f, RedisResult a) => [ByteString] -> m (f a)
#

sendRequest can be used to implement commands from experimental versions of Redis. An example of how to implement a command is given below.

-- |Redis DEBUG OBJECT command
debugObject :: ByteString -> Redis (Either Reply ByteString)
debugObject key = sendRequest ["DEBUG", "OBJECT", key]
datadata Reply
#

Low-level representation of replies from the Redis server.

Instances7Eq, Show, Generic, NFData, RedisResult, RedisCtx, …
datadata Status
#
Instances6Eq, Show, Generic, NFData, RedisResult, Rep
classclass RedisArg a where
#

Methods

Instances35RedisArg, …
classclass RedisResult a where
#

Methods

Instances58RedisResult, …
newtypenewtype HashSlot
#
Instances7Enum, Eq, Integral, Num, Ord, Real, …
  • Enum HashSlotDefined in hedis-0.16.4 · Database.Redis.Cluster.HashSlot
  • Eq HashSlotDefined in hedis-0.16.4 · Database.Redis.Cluster.HashSlot
  • Integral HashSlotDefined in hedis-0.16.4 · Database.Redis.Cluster.HashSlot
  • Num HashSlotDefined in hedis-0.16.4 · Database.Redis.Cluster.HashSlot
  • Ord HashSlotDefined in hedis-0.16.4 · Database.Redis.Cluster.HashSlot
  • Real HashSlotDefined in hedis-0.16.4 · Database.Redis.Cluster.HashSlot
  • Show HashSlotDefined in hedis-0.16.4 · Database.Redis.Cluster.HashSlot

Compute the hashslot associated with a key

Example6 expressions
keyToSlot "123"HashSlot 5970keyToSlot "{123"HashSlot 2872keyToSlot "{123}"HashSlot 5970keyToSlot "{}123"HashSlot 7640keyToSlot "{123}1{abc}"HashSlot 5970keyToSlot "\00\01"HashSlot 4129