Bridge function to run a worker under :mod:`multiprocessing`.

    The :mod:`multiprocessing` module cannot
    :meth:`~multiprocessing.Pool.apply_async` to a class constructor,
    even if the ``__init__`` calls ``.run()``, so this simple wrapper
    calls ``worker_class(*args, **kwargs)`` and logs any exceptions
    before re-raising them.

    This is usually only used to create a :class:`HeadlessWorker`, but
    it does run through the complete
    :meth:`~rejester.Worker.register`, :meth:`~rejester.Worker.run`,
    :meth:`~rejester.Worker.unregister` sequence with some logging
    on worker-level failures.

def run_worker(worker_class, *args, **kwargs):
    '''Bridge function to run a worker under :mod:`multiprocessing`.

    The :mod:`multiprocessing` module cannot
    :meth:`~multiprocessing.Pool.apply_async` to a class constructor,
    even if the ``__init__`` calls ``.run()``, so this simple wrapper
    calls ``worker_class(*args, **kwargs)`` and logs any exceptions
    before re-raising them.

    This is usually only used to create a :class:`HeadlessWorker`, but
    it does run through the complete
    :meth:`~rejester.Worker.register`, :meth:`~rejester.Worker.run`,
    :meth:`~rejester.Worker.unregister` sequence with some logging
    on worker-level failures.

    '''
    try:
        worker = worker_class(*args, **kwargs)
    except Exception:
        logger.critical('failed to create worker {0!r}'.format(worker_class),
                        exc_info=True)
        raise
    # A note on style here:
    #
    # If this runs ForkWorker, ForkWorker will os.fork() LoopWorker
    # (or SingleWorker) children, and the child will have this in its
    # call stack.  Eventually the child will sys.exit(), which raises
    # SystemExit, which is an exception that will trickle back through
    # here.  If there is a try:...finally: block, the finally: block
    # will execute on every child exit.  except Exception: won't run
    # on SystemExit.
    try:
        worker.register()
        worker.run()
        worker.unregister()
    except Exception:
        logger.error('worker {0!r} died'.format(worker_class), exc_info=True)
        try:
            worker.unregister()
        except:
            pass
        raise