At long last the Couchbase .NET SDK 2.1.0 GA is available! This release is a minor release for 2.1.0, but it includes support for the Task Asynchrony Pattern (async and await keywords) and non-blocking IO for all Key/Value operations. In addition, a number of other features have been included:
- Per connection TCP KEEP_ALIVE settings
- New extension points for creating “pluggable” Transcoders, Serializers and Converters
- Support for “Get and Touch” for sliding expirations on key/value pairs
- Official support for a “key exists” method
Other improvements and bug fixes include a fix for Replica Reads, a new query-request engine for handling inconsistencies and errors during swap/rebalance/failover scenarios and plethora of other bug fixes and improvements (over 45 Jira tickets closed). This release is JUGGED!
In the next couple of sections I’ll briefly go over the major features in this release; expect lengthier posts in the near future that dive deeper into each feature.
Task Asynchrony Pattern support for K/V
The entire IO engine was revamped in this release to support non-blocking IO; in order to take advantage of this feature we exposed it via the async and await keywords. If you are not familiar with the async/await keywords and the TAP (Task Asynchrony Pattern), you might want to jump over and read this, or this, or this before continuing.
Without going into too much detail (there will be deep dive in another, future post), here is an example of using async/await and the Couchbase SDK to insert and retrieve a key from a Couchbase cluster:
The first difference you will notice is the method signature now has the async keyword added to it; this will make it possible to use the await keyword within the method body. When the method runs, it will run synchronously until it reaches the await keyword, then it will be “lifted off” and run asynchronously. There is quite a bit of compiler magic involved here on the .NET side, but that is all you need to do to write asynchronous code using the Couchbase .NET SDK!
Within the Couchbase .NET SDK, a Task will be created and stored in queue; the request will be fired off to the Couchbase server in a “fire and forget” manner (via IOCP) and when it completes a callback will be fired which completes request by reading the response and returning it to the caller. If an error or exception occurs, it will be handled and returned as the IOperationResult implementation that the Task encapsulates. Once again, expect a deep-dive in a future post!
New Extension Points!
One goal of the 2.0 SDK was to provide extension points for the various components of the SDK; if you don’t like our implementation or the external API it’s based on, write your own! Another side positive effect is that it makes it easier to isolate and test various layers and components within the SDK.
In 2.1.1, we now support three new extension points:
- Serializers – handle serialization and deserialization of POCOs to JSON.
- Converters – handle the conversion of the Memcached byte packets going to and from the Couchbase server (and parity amongst the other SDK’s)
- Transcoders – handle the conversion and serialization/deserialization of the request or response body (the “value” part of “key/value”).
To create a custom serializer you implement the ITypeSerializer interface and provide a Func
Custom converters and transcoders can also be plugged-in as well by implementing the ITypeConverter or the ITypeTranscoder interfaces and providing a custom class that handles your specific use-case or need. Similarly to serializers, you then provide a Func
Expect future posts that dive deeper into these extensions points and illustrate how one would build and inject new transcoder, serializer and/or converter behavior into the client.
Other Features new to 2.1.0
Per connection settings for TCP KEEP-ALIVES
The default OS settings for TCP KEEP-ALIVES on Windows is 120 minutes. In some cases such as cloud deployments where Network Appliances (load balancers, etc) have been configured to kill TCP connections that have been idle for a shorter period time, we need a way to set the default TCP KEEP-ALIVES to a lower timespan. You can do this globally at the OS level via the Registry settings via KeepAliveInterval and KeepAliveTime, however, this will affect all applications running on that server. A better solution is to change the interval and time at the TCP connection level so that it only applies to connections that the client is usage.
Now it is possible to do so via the EnableTcpKeepAlives, TcpKeepAliveTime, and TcpKeepAliveInterval properties of the ClientConfiguration class. EnableTcpKeepAlives will enable or disable TCP KEEP-ALIVES (the default is enabled), TcpKeepAliveTime is the time that will elapse before KEEP-ALIVES are sent and TcpKeepAliveInterval is the interval between KEEP-ALIVES after the TcpKeepAliveTime is reached.
In the example above, before creating the Cluster object and opening a bucket from it, we create a ClientConfiguration and set the EnableTcpKeepAlives to true (note that the default is true, so this is just for illustration), the TcpKeepAliveTime is set to 1hr (this is when the first KEEP-ALIVE packet will be sent if the connection is idle), and finally we set the TcpKeepAliveInterVal to 5secs. What this means is that after 1hr of idleness, the client will start sending TCP KEEP-ALIVES every 5seconds until the connection becomes active again.
Support for Exists Method
Users often ask for a way of checking that a key exists without actually pulling the value back. We now have this support in v2.1.0. Both synchronis and asynchronous versions for this method are supported.
Support for GAT (Get and Touch) and Touch (for sliding expirations)
Two new methods were introduced: GetAndTouch and Touch. GetAndTouch will retrieve a value and update it's expiration and Touch will update the expiration of a key, but not return any value.
Important Bug Fixes
- Integer transcoding from 1.3.X to 2.X
- Fixes for Replica reads
- A lots and lots of bug fixes and improvements!
How to Get the Couchbase .NET SDK
The SDK is available for download directly, through NuGet, or by cloning and pulling the Github repo: