Hi,
Sorry for the long question.
I'm pretty new to Nameko and still trying to understand best practices.
Specifically, I'd like to know the best way to access DependencyProviders
in an complex application. Most of the nameko examples are single script
examples, so accessing Dependencies is fairly simple. I'm curious what the
best practice is for accessing Dependencies if you have a larger, more
complex application.
For example, let's say you have two scripts: *service.py* and *logic.py*.
*service.py* contains are nameko service, and *logic.py* contains our
application logic. If I want to access dependencies from *service.py* in
*logic.py*, then I have to pass those dependencies explicitly (see below)
#service.py
from nameko_sqlalchemy import Session
from namek_redis import Redis
from custom_logger import Logger # <-- I have a custom logger
DependencyProvider that takes care of mdc logging for me
from nameko.dependency_providers import Config
from logic import handle_process
class Service(object):
name = 'test'
session = Session(Base)
redis = Redis()
config = Config()
logger = Logger()
@rpc
def process(self, data):
handle_process(self.session, self.redis, self.config, self.logger,
data)
#logic.py
Logic(object):
@classmethod
def handle_process(cls, session, redis, config, logger, data):
DatabaseLogic.read_from_db(session, redis, config, logger, data)
DatabaseLogic(object):
@classmethod
def read_from_db(cls, session, redis, config, logger, data):
if config.dev:
try:
redis.get(data):
except:
session.query(data)
logger.info("Done reading from db")
As you can see, passing the dependencies around is pretty cumbersome, and
as you add more dependencies and more logic modules, it basically becomes
unreadable. The two possible fixes that I could imagine are:
1) Somehow you can access worker_ctx from any module (in the same you can
access a request from anywhere in a flask application):
from nameko.fake_module import current_worker_ctx
Logic(object):
@classmethod
def handle_process(cls, data):
DatabaseLogic.read_from_db(data)
DatabaseLogic(object):
@classmethod
def read_from_db(cls, data):
session = Session.get_dependency(current_worker_ctx)
redis = Redis.get_dependency(current_worker_ctx)
config = Config.get_dependency(current_worker_ctx)
logger = Logger.get_dependency(current_worker_ctx)
if config.dev:
try:
redis.get(data):
except:
session.query(data)
logger.info("Done reading from db")
2) Move away from DependencyProviders and create singleton classes that
allow you to access application objects anywhere in the application. For
example, my Database singleton might look like:
from sqlalchemy import create_engine
from sqlalchemy.orm import create_engine, sessionmaker
class _DatabaseManager(object):
def __init__(self):
self.engine = create_engine(...)
self.sessionmaker = sessionmaker(...)
@classmethod
def get_session(cls):
return scoped_session(self.sessionmaker) # scoped_session ensures
that the session is threadsafe
Database = _DatabaseManager()
This would allow me to call Database.get_session() from anywhere in my
application.
Any guidance here would be much appreciated because I'm sure I'm probably
thinking about something incorrectly!
Best,
Diego