Sanford TCP protocol server for hosting services. Define hosts for versioned services. Setup handlers for the services. Run the host as a daemon.
Sanford uses Sanford::Protocol to communicate with clients. Check out AndSon for a Ruby Sanford protocol client.
# define a host
class MyHost
include Sanford::Host
port 8000
pid_file '/path/to/host.pid'
# define some services
version 'v1' do
service 'get_user', 'MyHost::V1Services::GetUser'
end
end
# define handlers for the services
class MyHost::V1Services::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
To define a Sanford host, include the mixin Sanford::Host
on a class and use the DSL to configure it. A few options can be set:
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
.
Any values specified using the DSL act as defaults for instances of the host. You can overwritten when creating new instances:
host = MyHost.new({ :port => 12000 })
class MyHost
include Sanford::Host
version 'v1' do
service 'get_user', 'MyHost::ServicesV1::GetUser'
end
end
Services are defined on hosts by version. Each named service maps to a 'service handler' class. The version and service name are 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 MyHost
include Sanford::Host
version 'v1' do
service_handler_ns 'MyHost::ServicesV1'
service 'get_user', 'GetUser'
service 'get_article', 'GetArticle'
service 'get_comments', '::MyHost::OtherServices::GetComments'
end
end
Define handlers by mixing in Sanford::ServiceHandler
on a class and defining a run!
method:
class MyHost::Services::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 receivedparams
: returns the params payload from the request objecthalt
: stop processing and return response data with a status code and message
class MyHost::Services::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
Sanford comes with a CLI for running hosts:
sanford start
- spin up a background process running the host daemon.sanford stop
- shutdown the background process running the host gracefully.sanford restart
- "hot restart" the process running the host.sanford run
- starts the server, but doesn't daemonize it (runs in the current ruby process). Convenient when using the server in a development environment.
The basic commands are useful if your application only has one host defined and if you only want to run the host on a single port. In the case you have multiple hosts defined or you want to run a single host on multiple ports, use environment variables to set custom configurations.
sanford start # starts the first defined host
SANFORD_HOST=AnotherHost SANFORD_PORT=13001 sanford start # choose a specific host and port to run on with ENV vars
The CLI allow using environment variables for specifying which host to run the command against and for overriding the host's configuration. They recognize the a number of environment variables, but the main ones are: SANFORD_HOST
, SANFORD_IP
, and SANFORD_PORT
.
Define a name
on a Host to set a string name for your host that can be used to reference a host when using the CLI. If no name is set, Sanford will use the host's class name.
Alternatively, the CLI supports passing switches to override the host's configuration as well. Use sanford --help
to see the options that are available.
Typically, a Sanford host is part of a larger application and parts of the application need to be initialized or loaded when you start your Sanford server. To support this, Sanford provides an init
hook for hosts. The proc that is defined will be called before the Sanford server is started, properly running the server in your application's environment:
class MyHost
include Sanford::Host
init do
require File.expand_path("../config/environment", __FILE__)
end
end
- 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