README.md in net_tcp_client-1.0.2 vs README.md in net_tcp_client-2.0.0
- old
+ new
@@ -1,59 +1,245 @@
# net_tcp_client
-![](https://img.shields.io/gem/v/net_tcp_client.svg) ![](https://img.shields.io/travis/rocketjob/net_tcp_client.svg) ![](https://img.shields.io/gem/dt/net_tcp_client.svg) ![](https://img.shields.io/badge/status-production%20ready-blue.svg)
+[![Gem Version](https://img.shields.io/gem/v/net_tcp_client.svg)](https://rubygems.org/gems/net_tcp_client) [![Build Status](https://travis-ci.org/rocketjob/net_tcp_client.svg?branch=master)](https://travis-ci.org/rocketjob/net_tcp_client) [![Downloads](https://img.shields.io/gem/dt/net_tcp_client.svg)](https://rubygems.org/gems/net_tcp_client) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg) [![Gitter chat](https://img.shields.io/badge/IRC%20(gitter)-Support-brightgreen.svg)](https://gitter.im/rocketjob/support)
-Net::TCPClient is a TCP Socket Client with built-in timeouts, retries, and logging
+Net::TCPClient is a TCP Socket Client with automated failover, load balancing, retries and built-in timeouts.
* http://github.com/rocketjob/net_tcp_client
## Introduction
-Net::TCPClient implements resilience features that many developers wish was
+Net::TCPClient implements high availability and resilience features that many developers wish was
already included in the standard Ruby libraries.
-With so many "client" libraries to servers such us memcache, MongoDB, Redis, etc.
-their focus is on the communication formats and messaging interactions. As a result
-adding resilience is usually an after thought.
-
-More importantly the way that each client implements connection failure handling
-varies dramatically. The purpose of this library is to extract the best
-of all the socket error handling out there and create a consistent way of dealing
-with connection failures.
-
Another important feature is that the _connect_ and _read_ API's use timeout's to
prevent a network issue from "hanging" the client program.
-## Net::TCPClient API
+## Features
-Net::TCPClient is a drop in replacement for TCPSocket when used as a client.
+* Automated failover to another server.
+* Load balancing across multiple servers.
+* SSL and non-ssl connections.
+* Connect Timeout.
+* Read Timeout.
+* Write Timeout.
+* Fails over / load balances across all servers under a single DNS entry.
+* Logging.
+ * Optional trace level logging of all data sent or received.
+* Uses non blocking timeouts, instead of using threads such as used by the Timeout class.
+* Additional exceptions to distinguish between connection failures and timeouts.
+* Handshake callbacks.
+ * After a new connection has been established callbacks can be used
+ for handshakes such as authentication before data is sent.
-The initializer is the only deviation since it accepts several new options
-that support automatic failover, re-connect and messaging retries.
+### Example
-## Example
+~~~ruby
+require 'net/tcp_client'
-Connect to a server at address `localhost`, and on port `3300`.
+Net::TCPClient.connect(server: 'mydomain:3300') do |client|
+ client.send('Update the database')
+ response = client.read(20)
+ puts "Received: #{response}"
+end
+~~~
-Specify a custom retry interval and retry counts during connection.
+Enable SSL encryption:
-```ruby
+~~~ruby
require 'net/tcp_client'
+Net::TCPClient.connect(server: 'mydomain:3300', ssl: true) do |client|
+ client.send('Update the database')
+ response = client.read(20)
+ puts "Received: #{response}"
+end
+~~~
+
+## High Availability
+
+Net::TCPClient automatically tries each server in turn, should it fail to connect, or
+if the connection is lost the next server is tried immediately.
+
+Net::TCPClient detects DNS entries that have multiple IP Addresses associated with them and
+adds each of the ip addresses for the single DNS name to the list of servers to try to connect to.
+
+If a server is unavailable, cannot connect, or the connection is lost, the next server is immediately
+tried. Once all servers have been exhausted, it will keep trying to connect, starting with the
+first server again.
+
+When a connection is first established, and every time a connection is lost, Net::TCPClient
+uses connection policies to determine which server to connect to.
+
+## Load Balancing
+
+Using the connection policies client TCP connections can be balanced across multiple servers.
+
+## Connection Policies
+
+#### Ordered
+
+Servers are tried in the order they were supplied.
+
+~~~ruby
+tcp_client = Net::TCPClient.new(
+ servers: ['server1:3300', 'server2:3300', 'server3:3600']
+)
+~~~
+
+The servers will tried in the following order:
+`server1`, `server2`, `server3`
+
+`:ordered` is the default, but can be explicitly defined follows:
+
+~~~ruby
+tcp_client = Net::TCPClient.new(
+ servers: ['server1:3300', 'server2:3300', 'server3:3600'],
+ policy: :ordered
+)
+~~~
+
+#### Random
+
+Servers are tried in a Random order.
+
+~~~ruby
+tcp_client = Net::TCPClient.new(
+ servers: ['server1:3300', 'server2:3300', 'server3:3600'],
+ policy: :ordered
+)
+~~~
+
+No server is tried again until all of the others have been tried first.
+
+Example run, the servers could be tried in the following order:
+`server3`, `server1`, `server2`
+
+#### Custom defined order
+
+Supply your own custom order / load balancing algorithm for connecting to servers:
+
+Example:
+
+~~~ruby
+tcp_client = Net::TCPClient.new(
+ servers: ['server1:3300', 'server2:3300', 'server3:3600'],
+ policy: -> addresses, count do
+ # Return nil after the last address has been tried so that retry logic can take over
+ if count <= address.size
+ addresses.sample
+ end
+ end
+)
+~~~
+
+The above example returns addresses in random order without checking if a host name has been used before.
+
+It is important to check the count so that once all servers have been tried, it should return nil so that
+the retry logic can take over. Otherwise it will constantly try to connect to the servers without
+the retry delays etc.
+
+Example run, the servers could be tried in the following order:
+`server3`, `server1`, `server3`
+
+### Automatic Retry
+
+If a connection cannot be established to any servers in the list Net::TCPClient will retry from the
+first server. This retry behavior can be controlled using the following options:
+
+* `connect_retry_count` [Fixnum]
+ * Number of times to retry connecting when a connection fails
+ * Default: 10
+
+* `connect_retry_interval` [Float]
+ * Number of seconds between connection retry attempts after the first failed attempt
+ * Default: 0.5
+
+* `retry_count` [Fixnum]
+ * Number of times to retry when calling #retry_on_connection_failure
+ * This is independent of :connect_retry_count which still applies with
+ * connection failures. This retry controls upto how many times to retry the
+ * supplied block should a connection failure occur during the block
+ * Default: 3
+
+#### Note
+
+A server will only be retried again using the retry controls above once all other servers in the
+list have been exhausted.
+
+This means that if a connection is lost to a server that it will try to connect to a different server,
+not the same server unless it is the only server in the list.
+
+## Tuning
+
+If there are multiple servers in the list it is important to keep the `connect_timeout` low otherwise
+it can take a long time to find the next available server.
+
+## Retry on connection loss
+
+To transparently handle when a connection is lost after it has been established
+wrap calls that can be retried with `retry_on_connection_failure`.
+
+~~~ruby
Net::TCPClient.connect(
server: 'localhost:3300',
connect_retry_interval: 0.1,
connect_retry_count: 5
) do |client|
# If the connection is lost, create a new one and retry the send
client.retry_on_connection_failure do
- client.send('Update the database')
+ client.send('How many users available?')
+ response = client.read(20)
+ puts "Received: #{response}"
end
- response = client.read(20)
- puts "Received: #{response}"
end
-```
+~~~
+If the connection is lost during either the `send` or the `read` above the
+entire block will be re-tried once the connection has been re-stablished.
+
+## Callbacks
+
+Any time a connection has been established a callback can be called to handle activities such as:
+
+* Initialize per connection session sequence numbers.
+* Pass authentication information to the server.
+* Perform a handshake with the server.
+
+#### Authentication example:
+
+~~~ruby
+tcp_client = Net::TCPClient.new(
+ servers: ['server1:3300', 'server2:3300', 'server3:3600'],
+ on_connect: -> do |client|
+ client.send('My username and password')
+ result = client.read(2)
+ raise "Authentication failed" if result != 'OK'
+ end
+)
+~~~
+
+#### Per connection sequence number example:
+
+~~~ruby
+tcp_client = Net::TCPClient.new(
+ servers: ['server1:3300', 'server2:3300', 'server3:3600'],
+ on_connect: -> do |client|
+ # Set the sequence number to 0
+ user_data = 0
+ end
+)
+
+tcp_client.retry_on_connection_failure do
+ # Send with the sequence number
+ tcp_client.send("#{tcp_client.user_data} hello")
+ result = tcp_client.receive(30)
+
+ # Increment sequence number after every call to the server
+ tcp_client.user_data += 1
+end
+~~~
+
## Project Status
### Production Ready
Net::TCPClient is actively being used in a high performance, highly concurrent
@@ -62,64 +248,74 @@
## Installation
gem install net_tcp_client
-Although not required, it is recommended to use [Semantic Logger](http://rocketjob.github.io/semantic_logger) for logging purposes:
+To enable logging add [Semantic Logger](http://rocketjob.github.io/semantic_logger):
gem install semantic_logger
Or, add the following lines to you `Gemfile`:
-```ruby
- gem 'semantic_logger'
- gem 'net_tcp_client'
-```
+~~~ruby
+gem 'semantic_logger'
+gem 'net_tcp_client'
+~~~
To configure a stand-alone application for Semantic Logger:
-```ruby
+~~~ruby
require 'semantic_logger'
# Set the global default log level
SemanticLogger.default_level = :trace
# Log to a file, and use the colorized formatter
-SemanticLogger.add_appender('development.log', &SemanticLogger::Appender::Base.colorized_formatter)
-```
+SemanticLogger.add_appender(file_name: 'development.log', formatter: :color)
+~~~
If running Rails, see: [Semantic Logger Rails](http://rocketjob.github.io/semantic_logger/rails.html)
-Without Semantic Logger present a Ruby logger can be passed into Net::TCPClient.
+### Support
-### Upgrading from ResilientSocket
+Join the [Gitter chat session](https://gitter.im/rocketjob/support) if you have any questions.
+Issues / bugs can be reported via [Github issues](https://github.com/rocketjob/net_tcp_client/issues).
+
+### Upgrading to V2
+
+The following breaking changes have been made with V2:
+* The Connection timeout default is now 10 seconds, was 30 seconds.
+* To enable logging, add gem semantic_logger.
+ * The :logger option has been removed.
+* Deprecated option and attribute :server_selector has been removed.
+
+### Upgrading from ResilientSocket ![](https://img.shields.io/gem/dt/resilient_socket.svg)
+
ResilientSocket::TCPClient has been renamed to Net::TCPClient.
The API is exactly the same, just with a new namespace. Please upgrade to the new
`net_tcp_client` gem and replace all occurrences of `ResilientSocket::TCPClient`
with `Net::TCPClient` in your code.
## Supports
Tested and supported on the following Ruby platforms:
-- Ruby 1.9.3, 2.0, 2.1, 2.2 and above
-- JRuby 1.7, 9.0 and above
+- Ruby 2.1, 2.2, 2.3 and above
+- JRuby 1.7.23, 9.0 and above
- Rubinius 2.5 and above
There is a soft dependency on [Semantic Logger](http://github.com/rocketjob/semantic_logger). It will use SemanticLogger only if
it is already available, otherwise any other standard Ruby logger can be used.
### Note
Be sure to place the `semantic_logger` gem dependency before `net_tcp_client` in your Gemfile.
-## Versioning
-
-This project adheres to [Semantic Versioning](http://semver.org/).
-
## Author
[Reid Morrison](https://github.com/reidmorrison)
+
+[Contributors](https://github.com/rocketjob/net_tcp_client/graphs/contributors)
## Versioning
This project uses [Semantic Versioning](http://semver.org/).