Sanford
Sanford TCP protocol server for hosting services. Define servers for services. Setup handlers for the services. Run the server as a daemon.
Sanford uses Sanford::Protocol to communicate with clients. Check out AndSon for a Ruby Sanford protocol client.
Usage
# define a server
class MyServer
include Sanford::Server
port 8000
pid_file '/path/to/server.pid'
# define some services
router do
service 'get_user', 'MyServer::GetUser'
end
end
# define handlers for the services
class MyServer::GetUser
include Sanford::ServiceHandler
def run!
# process the service call and build a response
# the return value of this method will be used as the response data
end
end
Servers
To define a Sanford server, include the mixin Sanford::Server
on a class and use the DSL to configure it. A few options can be set:
-
name
- (string) A name for the server, this is used to set the process name and in logging. -
ip
- (string) A hostname or IP address for the server to bind to; default:'0.0.0.0'
. -
port
- (integer) The port number for the server to bind to. -
pid_file
- (string) Path to where you want the pid file to be written. -
logger
- (logger) A logger for Sanford to use when handling requests; default:Logger.new
.
Services
class MyServer
include Sanford::Server
router do
service 'get_user', 'MyServer::GetUser'
end
end
Services are defined on servers via a router block. Each named service maps to a 'service handler' class. The service name is used to 'route' requests to handler classes.
When defining services handlers, it's typical to organize them all under a common namespace. Use service_handler_ns
to define a default namespace for all handler classes under the version:
class MyServer
include Sanford::Server
router do
service_handler_ns 'MyServer'
service 'get_user', 'GetUser'
service 'get_article', 'GetArticle'
service 'get_comments', '::OtherServices::GetComments'
end
end
Service Handlers
Define handlers by mixing in Sanford::ServiceHandler
on a class and defining a run!
method:
class MyServer::GetUser
include Sanford::ServiceHandler
def run!
# process the service call and generate a response
# the return value of this method will be used as
# the response data returned to the client
end
end
This is the most basic way to define a service handler. In addition to this, the init!
method can be overwritten. This will be called after an instance of the service handler is created. The init!
method is intended as a hook to add constructor logic. The initialize
method should not be overwritten.
In addition to these, there are some helpers methods that can be used in your run!
method:
-
request
: returns the request object the host received -
params
: returns the params payload from the request object -
halt
: stop processing and return response data with a status code and message
class MyServer::GetUser
include Sanford::ServiceHandler
def run!
User.find(params['user_id']).attributes
rescue NotFoundException => e
halt :not_found, :message => e.message, :data => request.params
rescue Exception => e
halt :error, :message => e.message
end
end
Running Servers
To run a server, Sanford needs a config file to be defined:
require 'my_server'
run MyServer.new
This file works like a rackup file. You require in your server and call run
passing an instance of the server. To use these files, Sanford comes with a CLI:
-
sanford CONFIG_FILE start
- spin up a background process running the server. -
sanford CONFIG_FILE stop
- shutdown the background process running the server gracefully. -
sanford CONFIG_FILE restart
- "hot restart" the process running the server. -
sanford CONFIG_FILE run
- starts the server, but doesn't daemonize it (runs in the current ruby process). Convenient when using the server in a development environment.
Sanford will use the configuration of your server to either start a process or manage an existing one. A servers ip and port can be overwritten using environment variables:
sanford my_server.sanford start # starts a process for `MyServer`
SANFORD_IP="1.2.3.4" SANFORD_PORT=13001 sanford my_server.sanford start # run the same server on a custom ip and port
This allows running multiple instances of the same server on ips and ports that are different than its configuration if needed.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request