resilient_socket 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/resilient_socket/tcp_client.rb +164 -89
- data/lib/resilient_socket/version.rb +1 -1
- data/nbproject/private/config.properties +0 -0
- data/nbproject/private/private.properties +1 -0
- data/nbproject/project.properties +1 -0
- data/resilient_socket-0.0.2.gem +0 -0
- data/test/tcp_client_test.rb +38 -0
- data/test.log +0 -0
- metadata +4 -2
| @@ -35,13 +35,15 @@ module ResilientSocket | |
| 35 35 | 
             
                # due to a failed connection to the server
         | 
| 36 36 | 
             
                attr_accessor :user_data
         | 
| 37 37 |  | 
| 38 | 
            -
                # [String] Name of the server  | 
| 39 | 
            -
                # including the port number
         | 
| 38 | 
            +
                # Returns [String] Name of the server connected to including the port number
         | 
| 40 39 | 
             
                #
         | 
| 41 40 | 
             
                # Example:
         | 
| 42 | 
            -
                #    | 
| 41 | 
            +
                #   localhost:2000
         | 
| 43 42 | 
             
                attr_reader :server
         | 
| 44 43 |  | 
| 44 | 
            +
                # Returns [TrueClass|FalseClass] Whether send buffering is enabled for this connection
         | 
| 45 | 
            +
                attr_reader :buffered
         | 
| 46 | 
            +
             | 
| 45 47 | 
             
                # Create a connection, call the supplied block and close the connection on
         | 
| 46 48 | 
             
                # completion of the block
         | 
| 47 49 | 
             
                #
         | 
| @@ -116,6 +118,14 @@ module ResilientSocket | |
| 116 118 | 
             
                #     Number of seconds between connection retry attempts after the first failed attempt
         | 
| 117 119 | 
             
                #     Default: 0.5
         | 
| 118 120 | 
             
                #
         | 
| 121 | 
            +
                #   :on_connect [Proc]
         | 
| 122 | 
            +
                #     Directly after a connection is established and before it is made available
         | 
| 123 | 
            +
                #     for use this Block is invoked.
         | 
| 124 | 
            +
                #     Typical Use Cases:
         | 
| 125 | 
            +
                #     - Initialize per connection session sequence numbers
         | 
| 126 | 
            +
                #     - Pass any authentication information to the server
         | 
| 127 | 
            +
                #     - Perform a handshake with the server
         | 
| 128 | 
            +
                #
         | 
| 119 129 | 
             
                # Example
         | 
| 120 130 | 
             
                #   client = ResilientSocket::TCPClient.new(
         | 
| 121 131 | 
             
                #     :server                 => 'server:3300',
         | 
| @@ -127,7 +137,9 @@ module ResilientSocket | |
| 127 137 | 
             
                #     client.send('Update the database')
         | 
| 128 138 | 
             
                #   end
         | 
| 129 139 | 
             
                #
         | 
| 140 | 
            +
                #   # Read upto 20 characters from the server
         | 
| 130 141 | 
             
                #   response = client.read(20)
         | 
| 142 | 
            +
                #
         | 
| 131 143 | 
             
                #   puts "Received: #{response}"
         | 
| 132 144 | 
             
                #   client.close
         | 
| 133 145 | 
             
                def initialize(parameters={})
         | 
| @@ -138,8 +150,9 @@ module ResilientSocket | |
| 138 150 | 
             
                  @buffered = buffered.nil? ? true : buffered
         | 
| 139 151 | 
             
                  @connect_retry_count = params.delete(:connect_retry_count) || 10
         | 
| 140 152 | 
             
                  @connect_retry_interval = (params.delete(:connect_retry_interval) || 0.5).to_f
         | 
| 153 | 
            +
                  @on_connect = params.delete(:on_connect)
         | 
| 141 154 |  | 
| 142 | 
            -
                  unless @servers = params | 
| 155 | 
            +
                  unless @servers = params.delete(:servers)
         | 
| 143 156 | 
             
                    raise "Missing mandatory :server or :servers" unless server = params.delete(:server)
         | 
| 144 157 | 
             
                    @servers = [ server ]
         | 
| 145 158 | 
             
                  end
         | 
| @@ -168,47 +181,27 @@ module ResilientSocket | |
| 168 181 | 
             
                #    Timed out after 5 seconds trying to connect to the server
         | 
| 169 182 | 
             
                #    Usually means server is busy or the remote server disappeared off the network recently
         | 
| 170 183 | 
             
                #    No retry, just raise a ConnectionTimeout
         | 
| 184 | 
            +
                #
         | 
| 185 | 
            +
                # Note: When multiple servers are supplied it will only try to connect to
         | 
| 186 | 
            +
                #       the subsequent servers once the retry count has been exceeded
         | 
| 187 | 
            +
                #
         | 
| 171 188 | 
             
                def connect
         | 
| 172 | 
            -
                   | 
| 173 | 
            -
             | 
| 174 | 
            -
                     | 
| 175 | 
            -
                      # TODO Implement failover to second server if connect fails
         | 
| 176 | 
            -
                      @server = @servers.first
         | 
| 177 | 
            -
             | 
| 178 | 
            -
                      host_name, port = @server.split(":")
         | 
| 179 | 
            -
                      port = port.to_i
         | 
| 180 | 
            -
                      address = Socket.getaddrinfo('localhost', nil, Socket::AF_INET)
         | 
| 181 | 
            -
             | 
| 182 | 
            -
                      socket = Socket.new(Socket.const_get(address[0][0]), Socket::SOCK_STREAM, 0)
         | 
| 183 | 
            -
                      socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) unless @buffered
         | 
| 184 | 
            -
             | 
| 185 | 
            -
                      # http://stackoverflow.com/questions/231647/how-do-i-set-the-socket-timeout-in-ruby
         | 
| 189 | 
            +
                  if @servers.size > 0
         | 
| 190 | 
            +
                    # Try each server in sequence
         | 
| 191 | 
            +
                    @servers.each_with_index do |server, server_id|
         | 
| 186 192 | 
             
                      begin
         | 
| 187 | 
            -
                         | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
                         | 
| 191 | 
            -
                        raise(ConnectionTimeout.new("Timedout after #{@connect_timeout} seconds trying to connect to #{host_name}:#{port}")) unless resp
         | 
| 192 | 
            -
                        begin
         | 
| 193 | 
            -
                          socket_address = Socket.pack_sockaddr_in(port, address[0][3])
         | 
| 194 | 
            -
                          socket.connect_nonblock(socket_address)
         | 
| 195 | 
            -
                        rescue Errno::EISCONN
         | 
| 196 | 
            -
                        end
         | 
| 197 | 
            -
                      end
         | 
| 198 | 
            -
                      @socket = socket
         | 
| 199 | 
            -
             | 
| 200 | 
            -
                    rescue SystemCallError => exception
         | 
| 201 | 
            -
                      if retries < @connect_retry_count
         | 
| 202 | 
            -
                        retries += 1
         | 
| 203 | 
            -
                        @logger.warn "Connection failure: #{exception.class}: #{exception.message}. Retry: #{retries}"
         | 
| 204 | 
            -
                        sleep @connect_retry_interval
         | 
| 205 | 
            -
                        retry
         | 
| 193 | 
            +
                        @socket = connect_to_server(server)
         | 
| 194 | 
            +
                      rescue ConnectionFailure => exc
         | 
| 195 | 
            +
                        # Raise Exception once it has also failed to connect to the last server
         | 
| 196 | 
            +
                        raise(exc) if @servers.size <= (server_id + 1)
         | 
| 206 197 | 
             
                      end
         | 
| 207 | 
            -
                      @logger.error "Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries"
         | 
| 208 | 
            -
                      raise ConnectionFailure.new("After #{retries} attempts: #{exception.class}: #{exception.message}")
         | 
| 209 198 | 
             
                    end
         | 
| 199 | 
            +
                  else
         | 
| 200 | 
            +
                    @socket = connect_to_server(@servers.first)
         | 
| 210 201 | 
             
                  end
         | 
| 211 | 
            -
             | 
| 202 | 
            +
             | 
| 203 | 
            +
                  # Invoke user supplied Block every time a new connection has been established
         | 
| 204 | 
            +
                  @on_connect.call(self) if @on_connect
         | 
| 212 205 | 
             
                  true
         | 
| 213 206 | 
             
                end
         | 
| 214 207 |  | 
| @@ -232,54 +225,6 @@ module ResilientSocket | |
| 232 225 | 
             
                  end
         | 
| 233 226 | 
             
                end
         | 
| 234 227 |  | 
| 235 | 
            -
                # Send data with retry logic
         | 
| 236 | 
            -
                #
         | 
| 237 | 
            -
                # On a connection failure, it will close the connection and retry the block
         | 
| 238 | 
            -
                # Returns immediately on exception ReadTimeout
         | 
| 239 | 
            -
                #
         | 
| 240 | 
            -
                # Note this method should only wrap a single standalone call to the server
         | 
| 241 | 
            -
                #      since it will automatically retry the entire block every time a
         | 
| 242 | 
            -
                #      connection failure is experienced
         | 
| 243 | 
            -
                #
         | 
| 244 | 
            -
                # Error handling is implemented as follows:
         | 
| 245 | 
            -
                #    Network failure during send of either the header or the body
         | 
| 246 | 
            -
                #    Since the entire message was not sent it is assumed that it will not be processed
         | 
| 247 | 
            -
                #    Close socket
         | 
| 248 | 
            -
                #    Retry 1 time using a new connection before raising a ConnectionFailure
         | 
| 249 | 
            -
                #
         | 
| 250 | 
            -
                # Example of a resilient request that could _modify_ data at the server:
         | 
| 251 | 
            -
                #
         | 
| 252 | 
            -
                # # Only the send is within the retry block since we cannot re-send once
         | 
| 253 | 
            -
                # # the send was successful
         | 
| 254 | 
            -
                #
         | 
| 255 | 
            -
                # Example of a resilient _read-only_ request:
         | 
| 256 | 
            -
                #
         | 
| 257 | 
            -
                # # Since the send can be sent many times it is safe to also put the receive
         | 
| 258 | 
            -
                # # inside the retry block
         | 
| 259 | 
            -
                #
         | 
| 260 | 
            -
                def retry_on_connection_failure
         | 
| 261 | 
            -
                  retries = 0
         | 
| 262 | 
            -
                  begin
         | 
| 263 | 
            -
                    connect if closed?
         | 
| 264 | 
            -
                    yield(self)
         | 
| 265 | 
            -
                  rescue ConnectionFailure => exception
         | 
| 266 | 
            -
                    close
         | 
| 267 | 
            -
                    if retries < 3
         | 
| 268 | 
            -
                      retries += 1
         | 
| 269 | 
            -
                      @logger.warn "#retry_on_connection_failure Connection failure: #{exception.message}. Retry: #{retries}"
         | 
| 270 | 
            -
                      connect
         | 
| 271 | 
            -
                      retry
         | 
| 272 | 
            -
                    end
         | 
| 273 | 
            -
                    @logger.error "#retry_on_connection_failure Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries"
         | 
| 274 | 
            -
                    raise ConnectionFailure.new("After #{retries} retry_on_connection_failure attempts: #{exception.class}: #{exception.message}")
         | 
| 275 | 
            -
                  rescue Exception => exc
         | 
| 276 | 
            -
                    # With any other exception we have to close the connection since the connection
         | 
| 277 | 
            -
                    # is now in an unknown state
         | 
| 278 | 
            -
                    close
         | 
| 279 | 
            -
                    raise exc
         | 
| 280 | 
            -
                  end
         | 
| 281 | 
            -
                end
         | 
| 282 | 
            -
             | 
| 283 228 | 
             
                # 4. TCP receive timeout:
         | 
| 284 229 | 
             
                #    Send was successful but receive timed out after X seconds (for example 10 seconds)
         | 
| 285 230 | 
             
                #    No data or partial data received ( for example header but no body )
         | 
| @@ -327,6 +272,88 @@ module ResilientSocket | |
| 327 272 | 
             
                  buffer
         | 
| 328 273 | 
             
                end
         | 
| 329 274 |  | 
| 275 | 
            +
                # Send and/or receive data with automatic retry on connection failure
         | 
| 276 | 
            +
                #
         | 
| 277 | 
            +
                # On a connection failure, it will close the connection and retry the block
         | 
| 278 | 
            +
                # Returns immediately on exception ReadTimeout
         | 
| 279 | 
            +
                #
         | 
| 280 | 
            +
                # 1. Example of a resilient _readonly_ request:
         | 
| 281 | 
            +
                #
         | 
| 282 | 
            +
                #    When reading data from a server that does not change state on the server
         | 
| 283 | 
            +
                #    Wrap both the send and the read with #retry_on_connection_failure
         | 
| 284 | 
            +
                #    since it is safe to send the same data twice to the server
         | 
| 285 | 
            +
                #
         | 
| 286 | 
            +
                #    # Since the send can be sent many times it is safe to also put the receive
         | 
| 287 | 
            +
                #    # inside the retry block
         | 
| 288 | 
            +
                #    value = client.retry_on_connection_failure do
         | 
| 289 | 
            +
                #      client.send("GETVALUE:count\n")
         | 
| 290 | 
            +
                #      client.read(20).strip.to_i
         | 
| 291 | 
            +
                #    end
         | 
| 292 | 
            +
                #
         | 
| 293 | 
            +
                # 2. Example of a resilient request that _modifies_ data on the server:
         | 
| 294 | 
            +
                #
         | 
| 295 | 
            +
                #    When changing state on the server, for example when updating a value
         | 
| 296 | 
            +
                #    Wrap _only_ the send with #retry_on_connection_failure
         | 
| 297 | 
            +
                #    The read must be outside the #retry_on_connection_failure since we must
         | 
| 298 | 
            +
                #    not retry the send if the connection fails during the #read
         | 
| 299 | 
            +
                #
         | 
| 300 | 
            +
                #    value = 45
         | 
| 301 | 
            +
                #    # Only the send is within the retry block since we cannot re-send once
         | 
| 302 | 
            +
                #    # the send was successful since the server may have made the change
         | 
| 303 | 
            +
                #    client.retry_on_connection_failure do
         | 
| 304 | 
            +
                #      client.send("SETVALUE:#{count}\n")
         | 
| 305 | 
            +
                #    end
         | 
| 306 | 
            +
                #    # Server returns "SAVED" if the call was successfull
         | 
| 307 | 
            +
                #    result = client.read(20).strip
         | 
| 308 | 
            +
                #
         | 
| 309 | 
            +
                # 3. Example of a resilient request that _modifies_ data on the server:
         | 
| 310 | 
            +
                #
         | 
| 311 | 
            +
                #    When changing state on the server, for example when updating a value
         | 
| 312 | 
            +
                #    Wrap _only_ the send with #retry_on_connection_failure
         | 
| 313 | 
            +
                #    The read must be outside the #retry_on_connection_failure since we must
         | 
| 314 | 
            +
                #    not retry the send if the connection fails during the #read
         | 
| 315 | 
            +
                #
         | 
| 316 | 
            +
                #    value = 45
         | 
| 317 | 
            +
                #    # Only the send is within the retry block since we cannot re-send once
         | 
| 318 | 
            +
                #    # the send was successful since the server may have made the change
         | 
| 319 | 
            +
                #    client.retry_on_connection_failure do
         | 
| 320 | 
            +
                #      client.send("SETVALUE:#{count}\n")
         | 
| 321 | 
            +
                #    end
         | 
| 322 | 
            +
                #    # Server returns "SAVED" if the call was successfull
         | 
| 323 | 
            +
                #    saved = (client.read(20).strip == 'SAVED')
         | 
| 324 | 
            +
                #
         | 
| 325 | 
            +
                #
         | 
| 326 | 
            +
                # Error handling is implemented as follows:
         | 
| 327 | 
            +
                #    If a network failure occurrs during the block invocation the block
         | 
| 328 | 
            +
                #    will be called again with a new connection to the server.
         | 
| 329 | 
            +
                #    It will only be retried up to 3 times
         | 
| 330 | 
            +
                #    The re-connect will independently retry and timeout using all the
         | 
| 331 | 
            +
                #    rules of #connect
         | 
| 332 | 
            +
                #
         | 
| 333 | 
            +
                #
         | 
| 334 | 
            +
                def retry_on_connection_failure
         | 
| 335 | 
            +
                  retries = 0
         | 
| 336 | 
            +
                  begin
         | 
| 337 | 
            +
                    connect if closed?
         | 
| 338 | 
            +
                    yield(self)
         | 
| 339 | 
            +
                  rescue ConnectionFailure => exception
         | 
| 340 | 
            +
                    close
         | 
| 341 | 
            +
                    if retries < 3
         | 
| 342 | 
            +
                      retries += 1
         | 
| 343 | 
            +
                      @logger.warn "#retry_on_connection_failure Connection failure: #{exception.message}. Retry: #{retries}"
         | 
| 344 | 
            +
                      connect
         | 
| 345 | 
            +
                      retry
         | 
| 346 | 
            +
                    end
         | 
| 347 | 
            +
                    @logger.error "#retry_on_connection_failure Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries"
         | 
| 348 | 
            +
                    raise ConnectionFailure.new("After #{retries} retry_on_connection_failure attempts: #{exception.class}: #{exception.message}")
         | 
| 349 | 
            +
                  rescue Exception => exc
         | 
| 350 | 
            +
                    # With any other exception we have to close the connection since the connection
         | 
| 351 | 
            +
                    # is now in an unknown state
         | 
| 352 | 
            +
                    close
         | 
| 353 | 
            +
                    raise exc
         | 
| 354 | 
            +
                  end
         | 
| 355 | 
            +
                end
         | 
| 356 | 
            +
             | 
| 330 357 | 
             
                # Close the socket
         | 
| 331 358 | 
             
                #
         | 
| 332 359 | 
             
                # Logs a warning if an error occurs trying to close the socket
         | 
| @@ -346,6 +373,54 @@ module ResilientSocket | |
| 346 373 | 
             
                  @socket.setsockopt(level, optname, optval)
         | 
| 347 374 | 
             
                end
         | 
| 348 375 |  | 
| 349 | 
            -
             | 
| 376 | 
            +
                #############################################
         | 
| 377 | 
            +
                protected
         | 
| 378 | 
            +
             | 
| 379 | 
            +
                # Try connecting to a single server
         | 
| 380 | 
            +
                # Returns the connected socket
         | 
| 381 | 
            +
                #
         | 
| 382 | 
            +
                # Raises ConnectionTimeout when the connection timeout has been exceeded
         | 
| 383 | 
            +
                # Raises ConnectionFailure
         | 
| 384 | 
            +
                def connect_to_server(server)
         | 
| 385 | 
            +
                  socket = nil
         | 
| 386 | 
            +
                  retries = 0
         | 
| 387 | 
            +
                  @logger.benchmark_info "Connecting to server #{server}" do
         | 
| 388 | 
            +
                    begin
         | 
| 389 | 
            +
                      host_name, port = server.split(":")
         | 
| 390 | 
            +
                      port = port.to_i
         | 
| 391 | 
            +
                      address = Socket.getaddrinfo('localhost', nil, Socket::AF_INET)
         | 
| 392 | 
            +
             | 
| 393 | 
            +
                      socket = Socket.new(Socket.const_get(address[0][0]), Socket::SOCK_STREAM, 0)
         | 
| 394 | 
            +
                      socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) unless buffered
         | 
| 395 | 
            +
             | 
| 396 | 
            +
                      # http://stackoverflow.com/questions/231647/how-do-i-set-the-socket-timeout-in-ruby
         | 
| 397 | 
            +
                      begin
         | 
| 398 | 
            +
                        socket_address = Socket.pack_sockaddr_in(port, address[0][3])
         | 
| 399 | 
            +
                        socket.connect_nonblock(socket_address)
         | 
| 400 | 
            +
                      rescue Errno::EINPROGRESS
         | 
| 401 | 
            +
                        resp = IO.select(nil, [socket], nil, @connect_timeout)
         | 
| 402 | 
            +
                        raise(ConnectionTimeout.new("Timedout after #{@connect_timeout} seconds trying to connect to #{host_name}:#{port}")) unless resp
         | 
| 403 | 
            +
                        begin
         | 
| 404 | 
            +
                          socket_address = Socket.pack_sockaddr_in(port, address[0][3])
         | 
| 405 | 
            +
                          socket.connect_nonblock(socket_address)
         | 
| 406 | 
            +
                        rescue Errno::EISCONN
         | 
| 407 | 
            +
                        end
         | 
| 408 | 
            +
                      end
         | 
| 409 | 
            +
                      break
         | 
| 410 | 
            +
                    rescue SystemCallError => exception
         | 
| 411 | 
            +
                      if retries < @connect_retry_count
         | 
| 412 | 
            +
                        retries += 1
         | 
| 413 | 
            +
                        @logger.warn "Connection failure: #{exception.class}: #{exception.message}. Retry: #{retries}"
         | 
| 414 | 
            +
                        sleep @connect_retry_interval
         | 
| 415 | 
            +
                        retry
         | 
| 416 | 
            +
                      end
         | 
| 417 | 
            +
                      @logger.error "Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries"
         | 
| 418 | 
            +
                      raise ConnectionFailure.new("After #{retries} attempts: #{exception.class}: #{exception.message}")
         | 
| 419 | 
            +
                    end
         | 
| 420 | 
            +
                  end
         | 
| 421 | 
            +
                  @server = server
         | 
| 422 | 
            +
                  socket
         | 
| 423 | 
            +
                end
         | 
| 350 424 |  | 
| 425 | 
            +
              end
         | 
| 351 426 | 
             
            end
         | 
| 
            File without changes
         | 
| Binary file | 
    
        data/test/tcp_client_test.rb
    CHANGED
    
    | @@ -95,6 +95,44 @@ class TCPClientTest < Test::Unit::TestCase | |
| 95 95 | 
             
                    end
         | 
| 96 96 |  | 
| 97 97 | 
             
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  context "without client connection" do
         | 
| 100 | 
            +
                    should "connect to second server when first is down" do
         | 
| 101 | 
            +
                      client = ResilientSocket::TCPClient.new(
         | 
| 102 | 
            +
                        :servers         => ['localhost:1999', @server_name],
         | 
| 103 | 
            +
                        :read_timeout    => 3
         | 
| 104 | 
            +
                      )
         | 
| 105 | 
            +
                      assert_equal @server_name, client.server
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                      request = { 'action' => 'test1' }
         | 
| 108 | 
            +
                      client.send(BSON.serialize(request))
         | 
| 109 | 
            +
                      reply = read_bson_document(client)
         | 
| 110 | 
            +
                      assert_equal 'test1', reply['result']
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                      client.close
         | 
| 113 | 
            +
                    end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                    should "call on_connect after connection" do
         | 
| 116 | 
            +
                      client = ResilientSocket::TCPClient.new(
         | 
| 117 | 
            +
                        :server          => @server_name,
         | 
| 118 | 
            +
                        :read_timeout    => 3,
         | 
| 119 | 
            +
                        :on_connect      => Proc.new do |socket|
         | 
| 120 | 
            +
                          # Reset user_data on each connection
         | 
| 121 | 
            +
                          socket.user_data = { :sequence => 1 }
         | 
| 122 | 
            +
                        end
         | 
| 123 | 
            +
                      )
         | 
| 124 | 
            +
                      assert_equal @server_name, client.server
         | 
| 125 | 
            +
                      assert_equal 1, client.user_data[:sequence]
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                      request = { 'action' => 'test1' }
         | 
| 128 | 
            +
                      client.send(BSON.serialize(request))
         | 
| 129 | 
            +
                      reply = read_bson_document(client)
         | 
| 130 | 
            +
                      assert_equal 'test1', reply['result']
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                      client.close
         | 
| 133 | 
            +
                    end
         | 
| 134 | 
            +
                  end
         | 
| 135 | 
            +
             | 
| 98 136 | 
             
                end
         | 
| 99 137 |  | 
| 100 138 | 
             
              end
         | 
    
        data/test.log
    CHANGED
    
    | Binary file | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: resilient_socket
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0 | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2012-10- | 
| 12 | 
            +
            date: 2012-10-04 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: semantic_logger
         | 
| @@ -39,6 +39,7 @@ files: | |
| 39 39 | 
             
            - lib/resilient_socket/version.rb
         | 
| 40 40 | 
             
            - lib/resilient_socket.rb
         | 
| 41 41 | 
             
            - LICENSE.txt
         | 
| 42 | 
            +
            - nbproject/private/config.properties
         | 
| 42 43 | 
             
            - nbproject/private/private.properties
         | 
| 43 44 | 
             
            - nbproject/private/rake-d.txt
         | 
| 44 45 | 
             
            - nbproject/project.properties
         | 
| @@ -46,6 +47,7 @@ files: | |
| 46 47 | 
             
            - Rakefile
         | 
| 47 48 | 
             
            - README.md
         | 
| 48 49 | 
             
            - resilient_socket-0.0.1.gem
         | 
| 50 | 
            +
            - resilient_socket-0.0.2.gem
         | 
| 49 51 | 
             
            - test/simple_tcp_server.rb
         | 
| 50 52 | 
             
            - test/tcp_client_test.rb
         | 
| 51 53 | 
             
            - test.log
         |