API Documentation

Running your Application

This library exposes a utility function named sprockets.http.run() for running your application. You need to pass in a callable that accepts keyword parameters destined for tornado.web.Application and return the application instance.

sprockets.http.run(create_application, settings=None, log_config=<object object>)[source]

Run a Tornado create_application.

Parameters
  • create_application – function to call to create a new application instance

  • settings (dict|None) – optional configuration dictionary that will be passed through to create_application as kwargs.

  • log_config (dict|None) – optional logging configuration dictionary to use. By default, a reasonable logging configuration is generated based on settings. If you need to override the configuration, then use this parameter. It is passed as-is to logging.config.dictConfig().

settings[‘debug’]

If the settings parameter includes a value for the debug key, then the application will be run in Tornado debug mode.

If the settings parameter does not include a debug key, then debug mode will be enabled based on the DEBUG environment variable.

settings[‘port’]

If the settings parameter includes a value for the port key, then the application will be configured to listen on the specified port. If this key is not present, then the PORT environment variable determines which port to bind to. The default port is 8000 if nothing overrides it.

settings[‘number_of_procs’]

If the settings parameter includes a value for the number_of_procs key, then the application will be configured to run this many processes unless in debug mode. This is passed to HTTPServer.start.

settings[‘xheaders’]

If the settings parameter includes a value for the xheaders key, then the application will be configured to use headers, like X-Real-IP, to get the user’s IP address instead of attributing all traffic to the load balancer’s IP address. When running behind a load balancer like nginx, it is recommended to pass xheaders=True. The default value is True if nothing overrides it.

Using sprockets.http.run
def create_application(**settings):
   return web.Application(
      [
         # add your handlers here
      ], **settings)

if __name__ == '__main__':
   sprockets.http.run(create_application)

Since sprockets.http.run() accepts any callable, you can pass a class instance in as well. The sprockets.http.app.Application is a specialization of tornado.web.Application that includes state management callbacks that work together with the run function and provide hooks for performing initialization and shutdown tasks.

The following example uses sprockets.http.app.Application as a base class to implement asynchronously connecting to a mythical database when the application starts.

Using the Application class
from tornado import locks, web
from sprockets.http import app, run

class Application(app.Application):
   def __init__(self, *args, **kwargs):
      handlers = [
         # insert your handlers here
      ]
      super().__init__(handlers, *args, **kwargs)
      self.ready_to_serve = locks.Event()
      self.ready_to_serve.clear()
      self.on_start_callbacks.append(self._connect_to_database)

   def _connect_to_database(self, _self, iol):
      def on_connected(future):
         if future.exception():
            iol.call_later(0.5, self._connect_to_database, _self, iol)
         else:
            self.ready_to_serve.set()

      future = dbconnector.connect()
      iol.add_future(future, on_connected)

if __name__ == '__main__':
   run(Application)

Implementing a ready_to_serve event is a useful paradigm for applications that need to asynchronously initialize before they can service requests. We can continue the example and add a /status endpoint that makes use of the event:

Implementing health checks
class StatusHandler(web.RequestHandler):
   @gen.coroutine
   def prepare(self):
      maybe_future = super().prepare()
      if concurrent.is_future(maybe_future):
         yield maybe_future
      if not self._finished and not self.application.ready_to_serve.is_set():
         self.set_header('Retry-After', '5')
         self.set_status(503, 'Not Ready')
         self.finish()

   def get(self):
      self.set_status(200)
      self.write(json.dumps({'status': 'ok'})

Before Run Callbacks

This set of callbacks is invoked after Tornado forks sub-processes (based on the number_of_procs setting) and before start() is called. Callbacks can safely access the IOLoop without causing the start() method to explode.

If any callback raises an exception, then the application is terminated before the IOLoop is started.

On Start Callbacks

This set of callbacks is invoked after Tornado forks sub-processes (using tornado.ioloop.IOLoop.spawn_callback()) and after start() is called.

Shutdown Callbacks

When the application receives a stop signal, it will run each of the callbacks before terminating the application instance. Exceptions raised by the callbacks are simply logged.

Testing your Application

The SprocketsHttpTestCase class makes it simple to test sprockets.http based applications. It knows how to call the appropriate callbacks at the appropriate time. Use this as a base class in place of AsyncHTTPTestCase and modify your get_app method to set self.app.

class sprockets.http.testing.SprocketsHttpTestCase(methodName: str = 'runTest')[source]

Test case that correctly runs a sprockets.http.app.Application.

This test case correctly starts and stops a sprockets.http Application by calling the start() and stop() methods during setUp and tearDown.

app

You are required to set this attribute in your get_app() implementation.

get_app()[source]

Override this method to create your application.

Make sure to set self.app before returning.

setUp()[source]

Hook method for setting up the test fixture before exercising it.

The sprockets.http application is started by calling the start() method after the application is created.

shutdown_limit = 0.25

Maximum number of seconds to wait for the application to shut down.

tearDown()[source]

Hook method for deconstructing the test fixture after exercising it.

The sprockets.http application is fully stopped by calling the stop() and running the ioloop before stopping the ioloop. The shutdown timing is configured using the shutdown_limit and wait_timeout variables.

wait_timeout = 0.05

Number of seconds to wait between checking for pending callbacks.

Response Logging

Version 0.5.0 introduced the sprockets.http.mixins module with two simple classes - LoggingHandler and ErrorLogger. Together they ensure that errors emitted from your handlers will be logged in a consistent manner. All too often request handlers simply call write_error to report a failure to the caller with code that looks something like:

class MyHandler(web.RequestHandler):

   def get(self):
      try:
         do_something()
      except Failure:
         self.send_error(500, reason='Uh oh')
         return

This makes debugging an application fun since your caller generally has more information about the failure than you do :/

By adding ErrorLogger into the inheritance chain, your error will be emitted to the application log as if you had written the following instead:

class MyHandler(web.RequestHandler):
   def initialize(self):
      super().initialize()
      self.logger = logging.getLogger('MyHandler')

   def get(self):
      try:
         do_something()
      except Failure:
         self.logger.error('%s %s failed with %d: %s',
                           self.request.method, self.request.uri,
                           500, 'Uh oh')
         self.send_error(500, reason='Uh oh')
         return

It doesn’t look like much, but the error reporting is a little more interesting than that – 4XX errors are reported as a warning, exceptions will include the stack traces, etc.

class sprockets.http.mixins.LoggingHandler[source]

Add self.logger.

Mix this into your inheritance chain to add a logger attribute unless one already exists.

logger

Instance of logging.Logger with the same name as the class.

class sprockets.http.mixins.ErrorLogger[source]

Log a message in send_error.

Mix this class into your inheritance chain to ensure that errors sent via tornado.web.RequestHandler.send_error() and tornado.web.RequestHandler.write_error() are written to the log.

Standardized Error Response Documents

Version 0.5.0 also introduced the ErrorWriter class which implements write_error to provide a standard machine-readable document response instead of the default HTML response that Tornado implements. If ContentMixin is being used as well, write_error will use send_response() to send the document, otherwise it is sent as JSON.

class sprockets.http.mixins.ErrorWriter[source]

Write error bodies out consistently.

Mix this class in to your inheritance chain to include error bodies in a machine-readable document format.

If ContentMixin is also in use, it will send the error response with it, otherwise the response is sent as a JSON document.

The error document has three simple properties:

type

This is the type of exception that occurred or null. It is only set when write_error() is invoked with a non-empty exc_info parameter. In that case, it is set to the name of the first value in the tuple; IOW, exc_type.__name__.

message

This is a description of the error. If exception info is present, then the stringified exception value is used as the message (e.g., str(exc_value)); otherwise, the HTTP reason will be used. If a custom reason is not present, then the standard HTTP reason phrase is used. In the final case of a non-standard HTTP status code with neither an exception nor a custom reason, the string Unknown will be used.

traceback

If the application is configured to serve tracebacks and the error was caused by an exception (based on exc_info kwarg), then this is the formatted traceback as an array of strings returned from traceback.format_exception(). Otherwise, this property is set to null.

Internal Interfaces

Run a Tornado HTTP service.

  • Runner: encapsulates the running of the application

  • RunCommand: distutils command to runs an application

class sprockets.http.runner.RunCommand(dist)[source]

Simple distutils.Command that calls sprockets.http.run()

This is installed as the httprun distutils command when you install the sprockets.http module.

finalize_options()[source]

Set final values for all the options that this command supports. This is always called as late as possible, ie. after any option assignments from the command-line or from other commands have been done. Thus, this is the place to code option dependencies: if ‘foo’ depends on ‘bar’, then it is safe to set ‘foo’ from ‘bar’ as long as ‘foo’ still has the same value it was assigned in ‘initialize_options()’.

This method must be implemented by all command classes.

initialize_options()[source]

Set default values for all the options that this command supports. Note that these defaults may be overridden by other commands, by the setup script, by config files, or by the command-line. Thus, this is not the place to code dependencies between options; generally, ‘initialize_options()’ implementations are just a bunch of “self.foo = None” assignments.

This method must be implemented by all command classes.

run()[source]

A command’s raison d’etre: carry out the action it exists to perform, controlled by the options initialized in ‘initialize_options()’, customized by other commands, the setup script, the command-line, and config files, and finalized in ‘finalize_options()’. All terminal output and filesystem interaction should be done by ‘run()’.

This method must be implemented by all command classes.

class sprockets.http.runner.Runner(app, before_run=None, on_start=None, shutdown=None)[source]

HTTP service runner.

Parameters

app (tornado.web.Application) – the application to serve

This class implements the logic necessary to safely run a Tornado HTTP service inside of a docker container.

Usage Example

def make_app():
    return web.Application(...)

def run():
    server = runner.Runner(make_app())
    server.start_server()
    ioloop.IOLoop.instance().start()

The start_server() method sets up the necessary signal handling to ensure that we have a clean shutdown in the face of signals.

run(port_number, number_of_procs=0)[source]

Create the server and run the IOLoop.

Parameters
  • port_number (int) – the port number to bind the server to

  • number_of_procs (int) – number of processes to pass to Tornado’s httpserver.HTTPServer.start.

If the application’s debug setting is True, then we are going to run in a single-process mode; otherwise, we’ll let tornado decide how many sub-processes based on the value of the number_of_procs argument. In any case, the application’s before_run callbacks are invoked. If a callback raises an exception, then the application is terminated by calling sys.exit().

If any on_start callbacks are registered, they will be added to the Tornado IOLoop for execution after the IOLoop is started.

The following additional configuration parameters can be set on the httpserver.HTTPServer instance by setting them in the application settings: xheaders, max_body_size, max_buffer_size.

start_server(port_number, number_of_procs=0)[source]

Create a HTTP server and start it.

Parameters
  • port_number (int) – the port number to bind the server to

  • number_of_procs (int) – number of processes to pass to Tornado’s httpserver.HTTPServer.start.

If the application’s debug setting is True, then we are going to run in a single-process mode; otherwise, we’ll let tornado decide how many sub-processes to spawn.

The following additional configuration parameters can be set on the httpserver.HTTPServer instance by setting them in the application settings: xheaders, max_body_size, max_buffer_size.

stop_server()[source]

Stop the HTTP Server

class sprockets.http.app.Application(*args, **kwargs)[source]

Callback-aware version of tornado.web.Application.

Using this class instead of the vanilla Tornado Application class provides a clean way to customize application-level constructs such as connection pools.

Note that much of the functionality is implemented in CallbackManager.

log_request(handler)[source]

Customized access log function.

Parameters

handler (tornado.web.RequestHandler) –

class sprockets.http.app.CallbackManager(tornado_application, *args, **kwargs)[source]

Application state management.

This is where the core of the application wrapper actually lives. It is responsible for managing and calling the various application callbacks. Sub-classes are responsible for gluing in the actual tornado.web.Application object and the sprockets.http.runner module is responsible for starting up the HTTP stack and calling the start() and stop() methods.

runner_callbacks

dict of lists of callback functions to call at certain points in the application lifecycle. See before_run_callbacks, on_start_callbacks, and on_shutdown_callbacks.

Deprecated since version 1.4: Use the property callbacks instead of this dictionary. It will be going away in a future release.

property before_run_callbacks

List of synchronous functions called before the IOLoop is started.

The before_run callbacks are called after the IOLoop is created and before it is started. The callbacks are run synchronously and the application will exit if a callback raises an exception.

Signature: callback(application, io_loop)

property on_shutdown_callbacks

List of functions when the application is shutting down.

The on_shutdown callbacks are called after the HTTP server has been stopped. If a callback returns a tornado.concurrent.Future instance, then the future is added to the IOLoop.

Signature: callback(application)

property on_start_callbacks

List of asynchronous functions spawned before the IOLoop is started.

The on_start callbacks are spawned after the IOLoop is created and before it is started. The callbacks are run asynchronously via tornado.ioloop.IOLoop.spawn_callback() as soon as the IOLoop is started.

Signature: callback(application, io_loop)

start(io_loop)[source]

Run the before_run callbacks and queue to on_start callbacks.

Parameters

io_loop (tornado.ioloop.IOLoop) – loop to start the app on.

stop(io_loop, shutdown_limit=5.0, wait_timeout=1.0)[source]

Asynchronously stop the application.

Parameters
  • io_loop (tornado.ioloop.IOLoop) – loop to run until all callbacks, timeouts, and queued calls are complete

  • shutdown_limit (float) – maximum number of seconds to wait before terminating

  • wait_timeout (float) – number of seconds to wait between checks for pending callbacks & timers

Call this method to start the application shutdown process. The IOLoop will be stopped once the application is completely shut down or after shutdown_limit seconds.

property tornado_application

The underlying tornado.web.Application instance.

sprockets.http.app.wrap_application(application, before_run, on_start, shutdown)[source]

Wrap a tornado application in a callback-aware wrapper.

Parameters
  • application (tornado.web.Application) – application to wrap.

  • before_run (list|NoneType) – optional list of callbacks to invoke before the IOLoop is started.

  • on_start (list|NoneType) – optional list of callbacks to register with spawn_callback().

  • shutdown (list|NoneType) – optional list of callbacks to invoke before stopping the IOLoop

Returns

a wrapped application object

Return type

sprockets.http.app.Application