StackExchange.Redis
===================

StackExchange.Redis is a high performance general purpose redis client for .NET languages (C# etc). It is the logical successor to [BookSleeve](https://code.google.com/p/booksleeve/),
and is the client developed-by (and used-by) [Stack Exchange](http://stackexchange.com/) for busy sites like [Stack Overflow](http://stackoverflow.com/). For the full reasons
why this library was created (i.e. "What about BookSleeve?") [please see here](http://marcgravell.blogspot.com/2014/03/so-i-went-and-wrote-another-redis-client.html).

Note: this release should be considered "beta": the API may be subject  to minor changes.

Features
--

- High performance multiplexed design, allowing for efficient use of shared connections from multiple calling threads
- Abstraction over redis node configuration: the client can silently negotiate multiple redis servers for robustness and availability
- Convenient access to the full redis feature-set (caveat: scripting is still outstanding)
- Full dual programming model both synchronous and asynchronous usage, without requiring "sync over async" usage of the [TPL][1]
- Support for redis "cluster"

Installation
---

StackExchange.Redis can be installed via the nuget UI (as [StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis/)), or via the nuget package manager console:

    PM> Install-Package StackExchange.Redis

Usage
---

The central object in StackExchange.Redis is the `ConnectionMultiplexer` class in the `StackExchange.Redis` namespace; this is the object that hides away the details of multiple servers. Because the `ConnectionMultiplexer` does a lot, it is designed to be **shared and reused** between callers. You should not create a `ConnectionMultiplexer` per operation. It is fully thread-safe and ready for this usage. In all the subsequent examples it will be assumed that you have a `ConnectionMultiplexer` instance stored away for re-use. But for now, let's create one. This is done using `ConnectionMultiplexer.Connect` or `ConnectionMultiplexer.ConnectAsync`, passing in either a configuration string or a `ConfigurationOptions` object. The configuration string can take the form of a comma-delimited series of nodes, so let's just connect to an instance on the local machine on the default port (6379):

    using StackExchange.Redis;
    ...
    ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
    // ^^^ store and re-use this!!!

Note that `ConnectionMultiplexer` implements `IDisposable` and can be disposed when no longer required, but I am deliberately not showing `using` statement usage, because it is exceptionally rare that you would want to use a `ConnectionMultiplexer` briefly, as the idea is to re-use this object.

A more complicated scenario might involve a master/slave setup; for this usage, simply specify all the desired nodes that make up that logical redis tier (it will automatically identify the master):

    ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("server1:6379,server2:6379");

If it finds both nodes are masters, a tie-breaker key can optionally be specified that can be used to resolve the issue, however such a condition is fortunately very rare.

Once you have a `ConnectionMultiplexer`, there are 3 main things you might want to do:

- access a redis database (note that in the case of a cluster, a single logical database may be spread over multiple nodes)
- make use of the [pub/sub](http://redis.io/topics/pubsub) features of redis
- access an individual server for maintenance / monitoring purposes

Using a redis database
---

Accessing a redis database is as simple as:

    IDatabase db = redis.GetDatabase();

The object returned from `GetDatabase` is a cheap pass-thru object, and does not need to be stored. Note that redis supports multiple databases (although this is not supported on "cluster"); this can be optionally specified in the call to `GetDatabase`. Additionally, if you plan to make use of the asynchronous API and you require the [`Task.AsyncState`][2] to have a value, this can also be specified:

    int databaseNumber = ...
    object asyncState = ...
    IDatabase db = redis.GetDatabase(databaseNumber, asyncState);

Once you have the `IDatabase`, it is simply a case of using the [redis API](http://redis.io/commands). Note that all methods have both synchronous and asynchronous implementaions. In line with Microsoft's naming guidance, the asynchronous methods all end `...Async(...)`, and are fully `await`-able etc.

The simplest operation would be to store and retrieve a value:

    string value = "abcdefg";
    db.StringSet("mykey", value);
    ...
    string value = db.StringGet("mykey");
    Console.WriteLine(value); // writes: "abcdefg"

Note that the `String...` prefix here denotes the [String redis type](http://redis.io/topics/data-types), and is largely separate to the [.NET String type][3], although both can store text data. However, redis allows raw binary data for both keys and values - the usage is identical:

    byte[] key = ..., value = ...;
    db.StringSet(key, value);
    ...
    byte[] value = db.StringGet(key);

The entire range of [redis database commands](http://redis.io/commands) covering all redis data types is available for use.

Using redis pub/sub
----

Another common use of redis is as a [pub/sub message](http://redis.io/topics/pubsub) distribution tool; this too is simple, and in the event of connection failure, the `ConnectionMultiplexer` will handle all the details of re-subscribing to the requested channels.

    ISubscriber sub = redis.GetSubscriber();

Again, the object returned from `GetSubscriber` is a cheap pass-thru object that does not need to be stored. The pub/sub API has no concept of databases, but as before we can optionally provide an async-state. Note that all subscriptions are global: they are not scoped to the lifetime of the `ISubscriber` instance. The pub/sub features in redis use named "channels"; channels do not need to be defined in advance on the server (an interesting use here is things like per-user notification channels, which is what drives parts of the realtime updates on [Stack Overflow](http://stackoverflow.com)). As is common in .NET, subscriptions take the form of callback delegates which accept the channel-name and the message:

    sub.Subscribe("messages", (channel, message) => {
        Console.WriteLine((string)message);
    });

Separately (and often in a separate process on a separate machine) you can publish to this channel:

    sub.Publish("messages", "hello");

This will (virtually instantaneously) write `"hello"` to the console of the subscribed process. As before, both channel-names and messages can be binary.

Accessing individual servers
---

For maintenance purposes, it is sometimes necessary to issue server-specific commands:

    IServer server = redis.GetServer("localhost", 6379);

The `GetServer` method will accept an [`EndPoint`](http://msdn.microsoft.com/en-us/library/system.net.endpoint(v=vs.110).aspx) or the name/value pair that uniquely identify the server. As before, the object returned from `GetServer` is a cheap pass-thru object that does not to be stored, and async-state can be optionally specified. Note that the set of available endpoints is also available:

    EndPoint[] endpoints = redis.GetEndPoints();

From the `IServer` instance, the [Server commands](http://redis.io/commands#server) are available; for example:

    DateTime lastSave = server.LastSave();
    ClientInfo[] clients = server.ClientList();

Sync vs Async vs Fire-and-Forget
---

There are 3 primary usage mechanisms with StackExchange.Redis:

- Synchronous - where the operation completes before the methods returns to the caller (note that while this may block the caller, it absolutely **does not** block other threads: the key idea in StackExchange.Redis is that it aggressively shares the connection between concurrent callers)
- Asynchronous - where the operation completes some time in the future, and a `Task` or `Task<T>` is returned immediately, which can later:
 - be `.Wait()`ed (blocking the current thread until the response is available)
 - have a continuation callback added ([`ContinueWith`](http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.continuewith(v=vs.110).aspx) in the TPL)
 - be *awaited* (which is a language-level feature that simplfies the latter, while also continuing immediately if the reply is already known)
- Fire-and-Forget - where you really aren't interested in the reply, and are happy to continue irrespective of the response

The synchronous usage is already shown in the examples above. This is the simplest usage, and does not involve the [TPL][1].

For asynchronous uage, the key difference is the `Async` suffix on methods, and (typically) the use of the `await` language feature. For example:

    string value = "abcdefg";
    await db.StringSetAsync("mykey", value);
    ...
    string value = await db.StringGetAsync("mykey");
    Console.WriteLine(value); // writes: "abcdefg"

The fire-and-forget usage is accessed by the optional `CommandFlags flags` parameter on all methods (defaults to none). In this usage, the method returns the default value immediately (so a method that normally returns a `String` will always return `null`, and a method that normally returns an `Int64` will always return `0`). The operation will continue in the background. A typical use-case of this might be to increment page-view counts:

    db.StringIncrement(pageKey, flags: CommandFlags.FireAndForget);




  [1]: http://msdn.microsoft.com/en-us/library/dd460717%28v=vs.110%29.aspx
  [2]: http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.asyncstate(v=vs.110).aspx
  [3]: http://msdn.microsoft.com/en-us/library/system.string(v=vs.110).aspx