emmett-framework / emmett

The web framework for inventors
BSD 3-Clause "New" or "Revised" License
1.06k stars 71 forks source link

Running weppy on Pulsar (without picking App object) #190

Closed Triquetra closed 7 years ago

Triquetra commented 7 years ago

I've been having some issues getting weppy to work with Pulsar related to pickling, and it occurred to me that maybe an App instance is not pickleable?

gi0baro commented 7 years ago

@Triquetra short reply: yup, the App object is not pickle-able.

long reply: weppy does quite a LOT of things using that object and too many things are strictly dependant on the application object. For instance, in weppy there's no application context, 'cause the application objects is intended to be loaded and available before everything else. And since it's used by other internals, it cannot just be un-loaded and re-loaded again. Due to this, the application object is not pickle-able and should not be pickled-unpickled. I never used pulsar, but if you run in the need of pickling-unpickling the application object, I'm afraid you should switch instead to a destroy-recreation flow of the application object (but still I really don't know if it will work).

gi0baro commented 7 years ago

@Triquetra btw, have you tried to write a function which calls the app instead of passing the app directly to pulsar? eg:

def wsgi_call(*args, **kwargs):
     return app(*args, **kwargs)

# later in `pulsar_with_handler`
handler = wsgi.WsgiHandler([
    wsgi.wait_for_body_middleware, 
    wsgi.middleware_in_executor(wsgi_call)])
Triquetra commented 7 years ago

I just tried it, but it does not seem to work. I get the following error:

_pickle.PicklingError: Can't pickle <function wsgi_call at 0x000001F596AFC598>: it's not the same object as __main__.wsgi_call

Thank you for the prompt reply and idea. I would have preferred to use Pulsar, but if I can't get this to work without significant effort or weppy modification, I'll find a different server to use with weppy.

Triquetra commented 7 years ago

I got it working with some help from @Isbardel on the Pulsar issue queue. The solution is to use the LazyWSGI class to prevent pickling the callable. For example,

from weppy import App
from pulsar.apps import wsgi
app = App(__name__)

@app.route("/")
def hello():
    return "Hello WEPPY on Pulsar!"

class Site(wsgi.LazyWsgi):

    def setup(self, environ=None):
        mwie = wsgi.middleware_in_executor(app)
        handler = wsgi.WsgiHandler([wsgi.wait_for_body_middleware, mwie])
        return handler

if __name__ == "__main__":
    server = wsgi.WSGIServer(Site())
    server.start()