sprockets.http¶
The goal of this library is to make it a little easier to develop great HTTP API services using the Tornado web framework. It concentrates on running applications in a reliable & resilient manner and handling errors in a clean manner.
SIGTERM
is gracefully handled with respect to outstanding timeouts and callbacksListening port is configured by the
PORT
environment variable“Debug mode” is enabled by the
DEBUG
environment variablecatches
SIGINT
(e.g.,Ctrl+C
)application run in a single process
Running Your Application¶
Running a Tornado application intelligently should be very easy. Ideally your application wrapping code should look something like the following.
from tornado import web
import sprockets.http
def make_app(**settings):
return web.Application([
# insert your handlers
], **settings)
if __name__ == '__main__':
sprockets.http.run(make_app)
That’s it. The sprockets.http.run
function will set up signal
handlers and make sure that your application terminates gracefully
when it is sent either an interrupt or terminate signal.
It also takes care of configuring the standard logging module albeit in a opinionated way. The goal is to let you write your application without worrying about figuring out how to run and monitor it reliably.
If you are OO-minded, then you can also make use of a custom Application
class instead of writing a make_app
function:
import sprockets.http.app
class Application(sprockets.http.app.Application):
def __init__(self, *args, **kwargs):
handlers = [
# insert your handlers
]
super().__init__(handlers, *args, **kwargs)
if __name__ == '__main__':
sprockets.http.run(Application)
This approach is handy if you have application level state and logic that needs to be bundled together.
From setup.py¶
If you want, you can even run your application directly from setup.py
:
$ ./setup.py httprun -a mymodule:make_app
The httprun
command is installed as a distutils.command
when you
install the sprockets.http
package. This command accepts the following
command line parameters:
- application
The “callable” that returns your application. You want to specify whatever you are passing to
sprockets.http.run()
using a syntax similar to a setuptools console script. Basically, this is a string that contains the module name to import and the callable to invoke separated by a colon (e.g.,mypackage.module.submodule:function
). This is the only required parameter.- env-file
Optional name of a file containing environment variable definitions to parse and load into the environment before running the application. The file is a list of environment variables formatted as
name=value
with one setting on each line. If the line starts withexport
, then the export portion is removed (for the sake of convenience). If thevalue
portion is omitted, then the environment variable named will be removed from the environment if it is present.- port
Optional port number to bind the application to. This will set the
PORT
environment variable before running the application and after the environment file is read.
Error Logging¶
Handling errors should be simple as well. Tornado already does a great job of isolating the error handling into two methods on the request handler:
send_error is called by a request handler to send a HTTP error code to the caller. This is what you should be calling in your code. It handles setting the status, reporting the error, and finishing the request out.
write_error is called by
send_error
when it needs to send an error document to the caller. This should be overridden when you need to provide customized error pages. The important thing to realize is thatsend_error
callswrite_error
.
So your request handlers are already doing something like the following:
class MyHandler(web.RequestHandler):
def get(self):
try:
do_something()
except:
self.send_error(500, reason='Uh oh!')
return
In order for this to be really useful to you (the one that gets pinged when a failure happens), you need to have some information in your application logs that points to the problem. Cool… so do something like this then:
class MyHandler(web.RequestHandler):
def get(self):
try:
do_something()
except:
LOGGER.exception('do_something exploded for %s - returning %s',
self.request.uri, '500 Uh oh!')
self.send_error(500, reason='Uh oh!')
return
Simple enough. This works in the small, but think about how this approach scales. After a while your error handling might end up looking like:
class MyHandler(web.RequestHandler):
def get(self):
try:
do_something()
except SomethingSerious:
LOGGER.exception('do_something exploded for %s - returning %s',
self.request.uri, '500 Uh oh!')
self.send_error(500, reason='Uh oh!')
return
except SomethingYouDid:
LOGGER.exception('do_something exploded for %s - returning %s',
self.request.uri, '400 Stop That')
self.send_error(400, reason='Stop That')
return
Or maybe you are raising tornado.web.HTTPError instead of calling
send_error
– send_error will be called for you in this case.
The sprockets.http.mixins.ErrorLogger
mix-in extends write_error
to log the failure to the self.logger
BEFORE calling the super
implementation. This very simple piece of functionality ensures that when
your application is calling send_error
to signal errors you are writing
the failure out somewhere so you will have it later.
It is also nice enough to log 4xx status codes as warnings, 5xx codes as
errors, and include exception tracebacks if an exception is being handled.
You can go back to writing self.send_error
and let someone else keep
track of what happened.
Error Response Documents¶
Now that we have useful information in our log files, we should be returning
something useful as well. By default, the Tornado provided send_error
implementation writes a simple HTML file as the response body. The
sprockets.http.mixins.ErrorWriter
mix-in provides an implementation of
write_error
that is more amenable to programmatic usage. By default
it uses a JSON body since that is the defacto format these days. Let’s look
at our example again:
class MyHandler(web.RequestHandler):
def get(self):
try:
do_something()
except:
self.send_error(500, reason='Uh oh!')
return
The implementation of tornado.web.RequestHandler.write_error
will produce
a response that looks something like:
HTTP/1.1 500 Uh oh!
Server: TornadoServer/4.2.1
Content-Type: text/html; charset=UTF-8
Date: Fri, 20 Nov 2015 08:10:25 GMT
<html><title>500: Uh oh!</title><body>500: Uh oh!</body></html>
That is a lot better than nothing but not very useful when your user is
someone else’s code. By adding sprockets.http.mixins.ErrorWriter
to
the handler’s inheritance chain, we would get the following response
instead:
HTTP/1.1 500 Uh oh!
Server: TornadoServer/4.2.1
Content-Type: application/json
Date: Fri, 20 Nov 2015 08:10:25 GMT
{"message": "Uh oh!", "type": null, "traceback": null}
The traceback
and type
properties hint at the fact that exceptions
are handled in a manner similar to what Tornado would do – if the call to
send_error
includes exception information, then the exception’s type
will be included in the response. The traceback
is only included when
the standard serve_traceback
Tornado option is enabled.
If the sprockets.mixins.mediatype.ContentMixin
is also extended by your
base class, write-error
will use the ContentMixin.send_response
method
for choosing the appropriate response format and sending the error response.
License¶
Copyright (c) 2015-2020 AWeber Communications All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of Sprockets nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 theDEBUG
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 thePORT
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 toHTTPServer.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.
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.
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:
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.
See also
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.
See also
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.
See also
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()
andstop()
methods duringsetUp
andtearDown
.-
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 theshutdown_limit
andwait_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()
andtornado.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 whenwrite_error()
is invoked with a non-emptyexc_info
parameter. In that case, it is set to the name of the first value in thetuple
; 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 HTTPreason
will be used. If a customreason
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 stringUnknown
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 fromtraceback.format_exception()
. Otherwise, this property is set tonull
.
Internal Interfaces¶
Run a Tornado HTTP service.
Runner
: encapsulates the running of the applicationRunCommand
: 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
If the application’s
debug
setting isTrue
, 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 thenumber_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 callingsys.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
If the application’s
debug
setting isTrue
, 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
.
-
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 thesprockets.http.runner
module is responsible for starting up the HTTP stack and calling thestart()
andstop()
methods.-
runner_callbacks
¶ dict
of lists of callback functions to call at certain points in the application lifecycle. Seebefore_run_callbacks
,on_start_callbacks
, andon_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 toon_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
How to Contribute¶
Do you want to contribute fixes or improvements?
AWesome! Thank you very much, and let’s get started.
Quickstart Development Guide¶
Setup¶
code:
python3.10 -m venv env
pip install -r requires/development.txt
Testing¶
code:
coverage run
coverage report
Release History¶
2.4.0 (16 Mar 2022)¶
Add support for Python 3.10
Change the default access log format
2.3.0 (03 Feb 2022)¶
Added optional Sentry integration
2.2.0 (28 Sep 2020)¶
Change xheaders option to default to
True
2.1.2 (15 Sep 2020)¶
Updated to support Python 3.9.
asyncio.Task.all_tasks
was removed so I switched toasyncio.all_tasks
if it exists.Deprecate calling
sprockets.http.run
with anything that isn’t asprockets.app.Application
instance.
2.1.1 (19 Feb 2020)¶
sprockets.http.app.CallbackManager.stop()
no longer requires the event loop to be running (fixes #34)
2.1.0 (9 Oct 2019)¶
Make shutdown timings configurable.
Deprecate calling
sprockets.http.run()
without a specified logging configuration.
2.0.1 (5 Mar 2019)¶
Include Tornado 6 in pin
2.0.0 (27 Nov 2018)¶
Add support for Tornado 5.0
Drop support for Tornado versions earlier than 5.0
Drop support for Python versions earlier than 3.5
Remove logging from the signal handler. Logger’s cannot safely be used from within signal handlers. See Thread Safety in the logging module documentation for details.
1.5.0 (29 Jan 2018)¶
Enable port reuse for Tornado versions newer than 4.3.
1.4.2 (25 Jan 2018)¶
Allow max_body_size and max_buffer_size to be specified on the http server.
1.4.1 (3 Jan 2018)¶
Workaround https://bitbucket.org/birkenfeld/sphinx-contrib/issues/184/ by pinning sphinx in the development environment.
1.4.0 (29 Sep 2017)¶
Separate the concerns of running the application from the callback chains. The latter has been refactored into
sprockets.http.app
. This change is completely invisible to the outside world.Officially deprecated the
runner_callbacks
application attribute.
1.3.3 (20 Sept 2016)¶
Include correlation-id in the structured log data when logging.
1.3.2 (19 Sept 2016)¶
Include the service and environment (if set) in the structured log data.
1.3.1 (16 Sept 2016)¶
Change the non-DEBUG log format to include structured data and a leading first byte for log level.
1.3.0 (11 Mar 2016)¶
Add
httprun
setup.py command.Use
declare_namespace
to declare the sprockets namespace package.Remove
JSONRequestFormatter
logging when not in debug modeRemove sprockets.logging dependency
1.2.0 (11 Mar 2016)¶
Add support for the
on_start
callback.Add support to wait for the completion of
shutdown
callbacks that return a future.Adds new init params to runner.Runner for the three callback types
1.1.2 (23 Feb 2016)¶
Allow xheaders to be set in the application.settings.
1.1.1 (15 Feb 2016)¶
Delay grabbing the
IOLoop
instance until after fork.
1.1.0 (11 Feb 2016)¶
Add support for the
before_run
callback set.
1.0.2 (10 Dec 2015)¶
Add
log_config
parameter tosprockets.http.run
1.0.1 (20 Nov 2015)¶
Add support for
sprockets.mixins.mediatype
insprockets.http.mixins.ErrorWriter
1.0.0 (20 Nov 2015)¶
Add
sprockets.http.mixins.LoggingHandler
Add
sprockets.http.mixins.ErrorLogger
Add
sprockets.http.mixins.ErrorWriter
0.4.0 (24 Sep 2015)¶
Run callbacks from
application.runner_callbacks['shutdown']
when the application is shutting down.Add
number_of_procs
parameter tosprockets.http
.
0.3.0 (28 Aug 2015)¶
Install
sprockets.logging.tornado_log_function()
as the logging function when we are running in release mode
0.2.2 (23 Jul 2015)¶
Fixed requirements management… why is packaging so hard?!
0.2.1 (23 Jul 2015)¶
Corrected packaging metadata