Search code examples
python-asynciosanic

Trying to access an object from a listener python web framework


Pretty new to asynch so here is my question and thank you in advance. Hi All very simple question I might be thinking too much into.

I am trying to access this cassandra client outside of these defined listeners below that get registered to a sanic main app.

I need the session in order to use an update query which will execute Asynchronously. I can definetly connect and event query from the 'setup_cassandra_session_listener' method below. But having tough time figuring how to call this Cassandra session outside and isolate so i can access else where.

from aiocassandra import aiosession
from cassandra.cluster import Cluster
from sanic import Sanic
from config import  CLUSTER_HOST, TABLE_NAME, CASSANDRA_KEY_SPACE, CASSANDRA_PORT, DATA_CENTER, DEBUG_LEVEL,  LOGGER_FORMAT


log = logging.getLogger('sanic')
log.setLevel('INFO')


cassandra_cluster = None


def setup_cassandra_session_listener(app, loop):
    global cassandra_cluster

    cassandra_cluster = Cluster([CLUSTER_HOST], CASSANDRA_PORT, DATA_CENTER)
    session = cassandra_cluster.connect(CASSANDRA_KEY_SPACE)

    metadata = cassandra_cluster.metadata

    app.session = cassandra_cluster.connect(CASSANDRA_KEY_SPACE)
    log.info('Connected to cluster: ' + metadata.cluster_name)

    aiosession(session)
    app.cassandra = session


def teardown_cassandra_session_listener(app, loop):
    global cassandra_cluster
    cassandra_cluster.shutdown()


def register_cassandra(app: Sanic):
    app.listener('before_server_start')(setup_cassandra_session_listener)
    app.listener('after_server_stop')(teardown_cassandra_session_listener)

Solution

  • Here is a working example that should do what you need. It does not actually run Cassandra (since I have no experience doing that). But, in principle this should work with any database connection you need to manage across the lifespan of your running server.

    from sanic import Sanic
    from sanic.response import text
    
    app = Sanic()
    
    
    class DummyCluser:
        def connect(self):
            print("Connecting")
            return "session"
    
        def shutdown(self):
            print("Shutting down")
    
    
    def setup_cassandra_session_listener(app, loop):
        # No global variables needed
    
        app.cluster = DummyCluser()
        app.session = app.cluster.connect()
    
    
    def teardown_cassandra_session_listener(app, loop):
        app.cluster.shutdown()
    
    
    def register_cassandra(app: Sanic):
        # Changed these listeners to be more friendly if running with and ASGI server
        app.listener('after_server_start')(setup_cassandra_session_listener)
        app.listener('before_server_stop')(teardown_cassandra_session_listener)
    
    
    @app.get("/")
    async def get(request):
        return text(app.session)
    
    
    if __name__ == "__main__":
        register_cassandra(app)
        app.run(debug=True)
    

    The idea is that you attach to your app instance (as you did) and then are able to simply access that inside your routes with request.app.