View Source ThousandIsland (Thousand Island v0.6.4)
Thousand Island is a modern, pure Elixir socket server, inspired heavily by ranch. It aims to be easy to understand & reason about, while also being at least as stable and performant as alternatives.
Thousand Island is implemented as a supervision tree which is intended to be hosted
inside a host application, often as a dependency embedded within a higher-level
protocol library such as Bandit. Aside from
supervising the Thousand Island process tree, applications interact with Thousand
Island primarily via the ThousandIsland.Handler
behaviour.
handlers
Handlers
The ThousandIsland.Handler
behaviour defines the interface that Thousand Island
uses to pass ThousandIsland.Socket
s up to the application level; together they
form the primary interface that most applications will have with Thousand Island.
Thousand Island comes with a few simple protocol handlers to serve as examples;
these can be found in the examples
folder of this project. A simple implementation would look like this:
defmodule Echo do
use ThousandIsland.Handler
@impl ThousandIsland.Handler
def handle_data(data, socket, state) do
ThousandIsland.Socket.send(socket, data)
{:continue, state}
end
end
{:ok, pid} = ThousandIsland.start_link(port: 1234, handler_module: Echo)
For more information, please consult the ThousandIsland.Handler
documentation.
starting-a-thousand-island-server
Starting a Thousand Island Server
A typical use of ThousandIsland
might look like the following:
defmodule MyApp.Supervisor do
# ... other Supervisor boilerplate
def init(config) do
children = [
# ... other children as dictated by your app
{ThousandIsland, port: 1234, handler_module: MyApp.ConnectionHandler}
]
Supervisor.init(children, strategy: :one_for_one)
end
end
You can also start servers directly via the start_link/1
function:
{:ok, pid} = ThousandIsland.start_link(port: 1234, handler_module: MyApp.ConnectionHandler)
configuration
Configuration
A number of options are defined when starting a server. The complete list is
defined by the ThousandIsland.options/0
type.
connection-draining-shutdown
Connection Draining & Shutdown
ThousandIsland
instances are just a process tree consisting of standard
Supervisor, GenServer and Task modules, and so the usual rules regarding
shutdown and shutdown timeouts apply. Immediately upon beginning the shutdown
sequence the ThousandIsland.ShutdownListener process will cause the listening socket
to shut down, which in turn will cause all of the Acceptor
processes to shut
down as well. At this point all that is left in the supervision tree are several
layers of Supervisors and whatever Handler
processes were in progress when
shutdown was initiated. At this point, standard Supervisor shutdown timeout
semantics give existing connections a chance to finish things up. Handler
processes trap exit, so they continue running beyond shutdown until they either
complete or are :brutal_kill
ed after their shutdown timeout expires.
logging-telemetry
Logging & Telemetry
As a low-level library, Thousand Island purposely does not do any inline
logging of any kind. The ThousandIsland.Logger
module defines a number of
functions to aid in tracing connections at various log levels, and such logging
can be dynamically enabled and disabled against an already running server. This
logging is backed by telemetry events internally.
Thousand Island emits a rich set of telemetry events including spans for each
server, acceptor process, and individual client connection. These telemetry
events are documented in the ThousandIsland.Telemetry
module.
Link to this section Summary
Types
Possible options to configure a server. Valid option values are as follows
Functions
Gets a list of active connection processes. This is inherently a bit of a leaky notion in the face of concurrency, as there may be connections coming and going during the period that this function takes to run. Callers should account for the possibility that new connections may have been made since / during this call, and that processes returned by this call may have since completed. The order that connection processes are returned in is not specified
Returns information about the address and port that the server is listening on
Starts a ThousandIsland
instance with the given options. Returns a pid
that can be used to further manipulate the server via other functions defined on
this module in the case of success, or an error tuple describing the reason the
server was unable to start in the case of failure.
Synchronously stops the given server, waiting up to the given number of milliseconds for existing connections to finish up. Immediately upon calling this function, the server stops listening for new connections, and then proceeds to wait until either all existing connections have completed or the specified timeout has elapsed.
Link to this section Types
@type options() :: [ handler_module: module(), handler_options: term(), genserver_options: GenServer.options(), port: :inet.port_number(), transport_module: module(), transport_options: transport_options(), num_acceptors: pos_integer(), read_timeout: timeout(), shutdown_timeout: timeout() ]
Possible options to configure a server. Valid option values are as follows:
handler_module
: The name of the module used to handle connections to this server. The module is expected to implement theThousandIsland.Handler
behaviour. Required.handler_options
: A term which is passed as the initial state value toThousandIsland.Handler.handle_connection/2
calls. Optional, defaulting to nil.genserver_options
: A term which is passed as the value to the handler module's underlyingGenServer.start_link/3
call. Optional, defaulting to [].port
: The TCP port number to listen on. If not specified this defaults to 4000. If a port number of0
is given, the server will dynamically assign a port number which can then be obtained vialocal_info/1
.transport_module
: The name of the module which provides basic socket functions. Thousand Island providesThousandIsland.Transports.TCP
andThousandIsland.Transports.SSL
, which provide clear and TLS encrypted TCP sockets respectively. If not specified this defaults toThousandIsland.Transports.TCP
.transport_options
: A keyword list of options to be passed to the transport module'sThousandIsland.Transport.listen/2
function. Valid values depend on the transport module specified intransport_module
and can be found in the documentation for theThousandIsland.Transports.TCP
andThousandIsland.Transports.SSL
modules. Any options in terms of interfaces to listen to / certificates and keys to use for SSL connections will be passed in via this option.num_acceptors
: The number of acceptor processes to run. Defaults to 100.read_timeout
: How long to wait for client data before closing the connection, in milliseconds. Defaults to 60_000.shutdown_timeout
: How long to wait for existing client connections to complete before forcibly shutting those connections down at server shutdown time, in milliseconds. Defaults to 15_000. May also be:infinity
or:brutal_kill
as described in theSupervisor
documentation.
@type transport_options() :: ThousandIsland.Transports.TCP.options() | ThousandIsland.Transports.SSL.options()
Link to this section Functions
Gets a list of active connection processes. This is inherently a bit of a leaky notion in the face of concurrency, as there may be connections coming and going during the period that this function takes to run. Callers should account for the possibility that new connections may have been made since / during this call, and that processes returned by this call may have since completed. The order that connection processes are returned in is not specified
@spec listener_info(pid()) :: {:ok, ThousandIsland.Transport.socket_info()}
Returns information about the address and port that the server is listening on
@spec start_link(options()) :: Supervisor.on_start()
Starts a ThousandIsland
instance with the given options. Returns a pid
that can be used to further manipulate the server via other functions defined on
this module in the case of success, or an error tuple describing the reason the
server was unable to start in the case of failure.
Synchronously stops the given server, waiting up to the given number of milliseconds for existing connections to finish up. Immediately upon calling this function, the server stops listening for new connections, and then proceeds to wait until either all existing connections have completed or the specified timeout has elapsed.