tornado.stack_context — Exception handling across asynchronous callbacks¶

StackContext allows applications to maintain threadlocal-like statethat follows execution as it moves to other execution contexts.

The motivating examples are to eliminate the need for explicitasync_callback wrappers (as in tornado.web.RequestHandler), and toallow some additional context to be kept for logging.

This is slightly magic, but it’s an extension of the idea that anexception handler is a kind of stack-local state and when that stackis suspended and resumed in a new context that state needs to bepreserved. StackContext shifts the burden of restoring that statefrom each call site (e.g. wrapping each AsyncHTTPClient callbackin async_callback) to the mechanisms that transfer control fromone context to another (e.g. AsyncHTTPClient itself, IOLoop,thread pools, etc).

Example usage:

  1. @contextlib.contextmanager
    def die_on_error():
    try:
    yield
    except Exception:
    logging.error("exception in asynchronous operation",exc_info=True)
    sys.exit(1)

  2. with StackContext(die_on_error):

  3. # Any exception thrown here *or in callback and its descendants*
  4. # will cause the process to exit instead of spinning endlessly
  5. # in the ioloop.
  6. http_client.fetch(url, callback)
  7. ioloop.start()

Most applications shouldn’t have to work with StackContext directly.Here are a few rules of thumb for when it’s necessary:

  • If you’re writing an asynchronous library that doesn’t rely on astack_context-aware library like tornado.ioloop or tornado.iostream(for example, if you’re writing a thread pool), usestack_context.wrap() before any asynchronous operations to capture thestack context from where the operation was started.
  • If you’re writing an asynchronous library that has some sharedresources (such as a connection pool), create those shared resourceswithin a with stack_context.NullContext(): block. This will preventStackContexts from leaking from one request to another.
  • If you want to write something like an exception handler that willpersist across asynchronous calls, create a new StackContext (orExceptionStackContext), and make your asynchronous calls in a withblock that references your StackContext.
    class tornado.stackcontext.StackContext(_context_factory)[源代码]

    Establishes the given context as a StackContext that will be transferred.

Note that the parameter is a callable that returns a contextmanager, not the context itself. That is, where for anon-transferable context manager you would say:

  1. with my_context():

StackContext takes the function itself rather than its result:

  1. with StackContext(my_context):

The result of with StackContext() as cb: is a deactivationcallback. Run this callback when the StackContext is no longerneeded to ensure that it is not propagated any further (note thatdeactivating a context does not affect any instances of thatcontext that are currently pending). This is an advanced featureand not necessary in most applications.

class tornado.stackcontext.ExceptionStackContext(_exception_handler)[源代码]

Specialization of StackContext for exception handling.

The supplied exception_handler function will be called in theevent of an uncaught exception in this context. The semantics aresimilar to a try/finally clause, and intended use cases are to logan error, close a socket, or similar cleanup actions. Theexc_info triple (type, value, traceback) will be passed to theexception_handler function.

If the exception handler returns true, the exception will beconsumed and will not be propagated to other exception handlers.

class tornado.stack_context.NullContext[源代码]

Resets the StackContext.

Useful when creating a shared resource on demand (e.g. anAsyncHTTPClient) where the stack that caused the creating isnot relevant to future operations.

tornado.stackcontext.wrap(_fn)[源代码]

Returns a callable object that will restore the current StackContextwhen executed.

Use this whenever saving a callback to be executed later in adifferent execution context (either in a different thread orasynchronously in the same thread).

tornado.stackcontext.run_with_stack_context(_context, func)[源代码]

Run a coroutine func in the given StackContext.

It is not safe to have a yield statement within a with StackContextblock, so it is difficult to use stack context with gen.coroutine.This helper function runs the function in the correct context whilekeeping the yield and with statements syntactically separate.

Example:

  1. @gen.coroutine
    def incorrect():
    with StackContext(ctx):

  2.     # ERROR: this will raise StackContextInconsistentError
  3.     yield other_coroutine()
  4. @gen.coroutine
    def correct():
    yield run_with_stack_context(StackContext(ctx), other_coroutine)

3.1 新版功能.

原文:

https://tornado-zh-cn.readthedocs.io/zh_CN/latest/stack_context.html