# Buggy code
def create_native_worker_client_factory(router_session_factory, on_ready, on_exit):
    """
    Create a transport factory for talking to native workers.

    The node controller talks WAMP-WebSocket-over-STDIO with spawned (native) workers.

    The node controller runs a client transport factory, and the native worker
    runs a server transport factory. This is a little non-intuitive, but just the
    way that Twisted works when using STDIO transports.

    :param router_session_factory: Router session factory to attach to.
    :type router_session_factory: obj
    """
    factory = NativeWorkerClientFactory(
        router_session_factory, "ws://localhost", debug=False
    )

    # we need to increase the opening handshake timeout in particular, since starting up a worker
    # on PyPy will take a little (due to JITting)
    factory.setProtocolOptions(
        failByDrop=False, openHandshakeTimeout=30, closeHandshakeTimeout=5
    )

    # on_ready is resolved in crossbar/controller/process.py:on_worker_ready around 175
    # after crossbar.node.<ID>.on_worker_ready is published to (in the controller session)
    # that happens in crossbar/worker/worker.py:publish_ready which itself happens when
    # the native worker joins the realm (part of onJoin)
    factory._on_ready = on_ready
    factory._on_exit = on_exit

    return factory


# Traceback (ApplicationError)
$ crossbar init
$ crossbar start
2015-04-14 19:05:22+0000 [Controller   8740] Log opened.
2015-04-14 19:05:22+0000 [Controller   8740] ==================== Crossbar.io ====================

2015-04-14 19:05:22+0000 [Controller   8740] Crossbar.io 0.10.4 starting
2015-04-14 19:05:22+0000 [Controller   8740] Running on CPython using EPollReactor reactor
2015-04-14 19:05:22+0000 [Controller   8740] Starting from node directory /home/pi/cbtest/.crossbar
2015-04-14 19:05:25+0000 [Controller   8740] Starting from local configuration '/home/pi/cbtest/.crossbar/config.json'
2015-04-14 19:05:25+0000 [Controller   8740] Warning, could not set process title (setproctitle not installed)
2015-04-14 19:05:25+0000 [Controller   8740] Router created for realm 'crossbar'
2015-04-14 19:05:26+0000 [Controller   8740] No WAMPlets detected in enviroment.
2015-04-14 19:05:26+0000 [Controller   8740] Starting Router with ID 'worker1' ..
2015-04-14 19:05:26+0000 [Controller   8740] Entering reactor event loop ...
2015-04-14 19:05:28+0000 [Router       8749] /usr/local/lib/python2.7/dist-packages/zope.deprecation-4.1.2-py2.7.egg/zope/__init__.py:3: UserWarning: Module twisted was already imported from /usr/local/lib/python2.7/dist-packages/Twisted-15.1.0-py2.7-linux-armv6l.egg/twisted/__init__.pyc, but /usr/local/lib/python2.7/dist-packages/autobahn-0.10.3-py2.7.egg is being added to sys.path
2015-04-14 19:05:30+0000 [Router       8749] Log opened.
2015-04-14 19:05:30+0000 [Router       8749] Warning: could not set worker process title (setproctitle not installed)
2015-04-14 19:05:52+0000 [Router       8749] Running under CPython using EPollReactor reactor
2015-04-14 19:05:58+0000 [Controller   8740] Worker 8749: Process connection gone (A process has ended with a probable error condition: process ended with exit code 1.)
2015-04-14 19:05:58+0000 [Controller   8740] ERROR: failed to start native worker - A process has ended with a probable error condition: process ended with exit code 1.
2015-04-14 19:05:58+0000 [Controller   8740] Traceback (most recent call last):
2015-04-14 19:05:58+0000 [Controller   8740]   File "/usr/local/lib/python2.7/dist-packages/crossbar-0.10.4-py2.7.egg/crossbar/controller/node.py", line 183, in run_node_config
2015-04-14 19:05:58+0000 [Controller   8740]     yield self._run_node_config(config)
2015-04-14 19:05:58+0000 [Controller   8740]   File "/usr/local/lib/python2.7/dist-packages/Twisted-15.1.0-py2.7-linux-armv6l.egg/twisted/internet/defer.py", line 1105, in _inlineCallbacks
2015-04-14 19:05:58+0000 [Controller   8740]     result = result.throwExceptionIntoGenerator(g)
2015-04-14 19:05:58+0000 [Controller   8740]   File "/usr/local/lib/python2.7/dist-packages/Twisted-15.1.0-py2.7-linux-armv6l.egg/twisted/python/failure.py", line 389, in throwExceptionIntoGenerator
2015-04-14 19:05:58+0000 [Controller   8740]     return g.throw(self.type, self.value, self.tb)
2015-04-14 19:05:58+0000 [Controller   8740]   File "/usr/local/lib/python2.7/dist-packages/crossbar-0.10.4-py2.7.egg/crossbar/controller/node.py", line 249, in _run_node_config
2015-04-14 19:05:58+0000 [Controller   8740]     yield self._controller.start_router(worker_id, worker_options, details=call_details)
2015-04-14 19:05:58+0000 [Controller   8740]   File "/usr/local/lib/python2.7/dist-packages/Twisted-15.1.0-py2.7-linux-armv6l.egg/twisted/internet/defer.py", line 578, in _runCallbacks
2015-04-14 19:05:58+0000 [Controller   8740]     current.result = callback(current.result, *args, **kw)
2015-04-14 19:05:58+0000 [Controller   8740]   File "/usr/local/lib/python2.7/dist-packages/crossbar-0.10.4-py2.7.egg/crossbar/controller/process.py", line 540, in on_ready_error
2015-04-14 19:05:58+0000 [Controller   8740]     raise ApplicationError("crossbar.error.cannot_start", emsg, worker.getlog())
2015-04-14 19:05:58+0000 [Controller   8740] ApplicationError: ApplicationError('crossbar.error.cannot_start', args = ('ERROR: failed to start native worker - A process has ended with a probable error condition: process ended with exit code 1.', []), kwargs = {})
2015-04-14 19:05:58+0000 [Controller   8740] Main loop terminated.

# Fixed code
def create_native_worker_client_factory(router_session_factory, on_ready, on_exit):
    """
    Create a transport factory for talking to native workers.

    The node controller talks WAMP-WebSocket-over-STDIO with spawned (native) workers.

    The node controller runs a client transport factory, and the native worker
    runs a server transport factory. This is a little non-intuitive, but just the
    way that Twisted works when using STDIO transports.

    :param router_session_factory: Router session factory to attach to.
    :type router_session_factory: obj
    """
    factory = NativeWorkerClientFactory(
        router_session_factory, "ws://localhost", debug=False
    )

    # we need to increase the opening handshake timeout in particular, since starting up a worker
    # on PyPy will take a little (due to JITting)
    factory.setProtocolOptions(
        failByDrop=False, openHandshakeTimeout=60, closeHandshakeTimeout=5
    )

    # on_ready is resolved in crossbar/controller/process.py:on_worker_ready around 175
    # after crossbar.node.<ID>.on_worker_ready is published to (in the controller session)
    # that happens in crossbar/worker/worker.py:publish_ready which itself happens when
    # the native worker joins the realm (part of onJoin)
    factory._on_ready = on_ready
    factory._on_exit = on_exit

    return factory