DependencyProvider get_dependency specific to request

I have a use case where we have isolated databases for each client. That
means, when a request from a specific client comes in, I want to get access
to that client's specific database.

Let's say I have a database DependencyProvider (similar to
nameko_sqlalchemy), where the *setup *function instantiates all of my
connections to all of the client databases. I'm not entirely clear how I
can alter the worker_ctx in *get_dependency *so that I can return the
connection for a specific client. It seems like I somehow need to alter
worker_ctx so that I end up doing something like:

class Database(DependencyProvider):

    def setup(self):
        #Start all client connections

    def get_dependency(self, worker_ctx):
        client = worker_ctx['client_id']
        session_cls = sessionmaker(bind=self.connections[client])
        session = session_cls()
        self.session[worker_ctx] = session
        return session
       
Do you have any suggestions for how to do this?

Thanks!

You've got the right approach.

The WorkerContext has a `context_data` dict for carrying request-contextual
data like `session_id`, `locale` etc between calls. If you put the
`client_id` in there, it'll be available to all DependencyProviders in the
current service. It will also pass along between service calls if your
inter-service DependencyProviders and Entrypoints pass it along. See my
reply to your question here
<https://groups.google.com/forum/#!topic/nameko-dev/Jz2V0llSFJ0> for more.

···

On Wednesday, April 19, 2017 at 2:29:52 AM UTC+1, di...@clearmetal.com wrote:

I have a use case where we have isolated databases for each client. That
means, when a request from a specific client comes in, I want to get access
to that client's specific database.

Let's say I have a database DependencyProvider (similar to
nameko_sqlalchemy), where the *setup *function instantiates all of my
connections to all of the client databases. I'm not entirely clear how I
can alter the worker_ctx in *get_dependency *so that I can return the
connection for a specific client. It seems like I somehow need to alter
worker_ctx so that I end up doing something like:

class Database(DependencyProvider):

    def setup(self):
        #Start all client connections

    def get_dependency(self, worker_ctx):
        client = worker_ctx['client_id']
        session_cls = sessionmaker(bind=self.connections[client])
        session = session_cls()
        self.session[worker_ctx] = session
        return session
       
Do you have any suggestions for how to do this?

Thanks!

Hi Matt,

Thanks for the response. That's a solution I hadn't thought of, thanks for
posting it.

I'm curious whether you can achieve the same functionality with "logging
in" with a session. Can you alter the context data when you are making a
call from one service to another? For example, could I do something similar
to the following:

class Service1(object):
    name = 'service_1'
    service_2 = RpcProxy('service_2')

    @rpc
    def client_endpoint(self, client_id):
        data = {"data": "blah"}

        # SOME HOW PASS IN CONTEXT DATA HERE ??
        # self.worker_ctx.context_data['client_id'] = client_id
        self.service_2.write_to_database(client_id, data)

class Service2(object):
    name = 'service_2'
    session = Session(Base)

    @rpc
    def write_to_database(self):
        session = self.session # Uses context_data from client_endpoint to
get session specific to client

···

On Wednesday, April 19, 2017 at 12:26:32 AM UTC-7, Matt Yule-Bennett wrote:

You've got the right approach.

The WorkerContext has a `context_data` dict for carrying
request-contextual data like `session_id`, `locale` etc between calls. If
you put the `client_id` in there, it'll be available to all
DependencyProviders in the current service. It will also pass along between
service calls if your inter-service DependencyProviders and Entrypoints
pass it along. See my reply to your question here
<https://groups.google.com/forum/#!topic/nameko-dev/Jz2V0llSFJ0> for more.

On Wednesday, April 19, 2017 at 2:29:52 AM UTC+1, di...@clearmetal.com > wrote:

I have a use case where we have isolated databases for each client. That
means, when a request from a specific client comes in, I want to get access
to that client's specific database.

Let's say I have a database DependencyProvider (similar to
nameko_sqlalchemy), where the *setup *function instantiates all of my
connections to all of the client databases. I'm not entirely clear how I
can alter the worker_ctx in *get_dependency *so that I can return the
connection for a specific client. It seems like I somehow need to alter
worker_ctx so that I end up doing something like:

class Database(DependencyProvider):

    def setup(self):
        #Start all client connections

    def get_dependency(self, worker_ctx):
        client = worker_ctx['client_id']
        session_cls = sessionmaker(bind=self.connections[client])
        session = session_cls()
        self.session[worker_ctx] = session
        return session
       
Do you have any suggestions for how to do this?

Thanks!

Yes, you can do exactly this.

The only caveat is that service classes can't access the worker context
directly -- you'd need to modify it via a DependencyProvider (or use one to
expose it directly).

With this pattern, we sometimes use a context manager around the RPC proxy
call to set context data for that call and remove it again afterwards.

···

On Saturday, April 22, 2017 at 9:55:34 PM UTC+1, di...@clearmetal.com wrote:

Hi Matt,

Thanks for the response. That's a solution I hadn't thought of, thanks
for posting it.

I'm curious whether you can achieve the same functionality with "logging
in" with a session. Can you alter the context data when you are making a
call from one service to another? For example, could I do something similar
to the following:

class Service1(object):
    name = 'service_1'
    service_2 = RpcProxy('service_2')

    @rpc
    def client_endpoint(self, client_id):
        data = {"data": "blah"}

        # SOME HOW PASS IN CONTEXT DATA HERE ??
        # self.worker_ctx.context_data['client_id'] = client_id
        self.service_2.write_to_database(client_id, data)

class Service2(object):
    name = 'service_2'
    session = Session(Base)

    @rpc
    def write_to_database(self):
        session = self.session # Uses context_data from client_endpoint to
get session specific to client

On Wednesday, April 19, 2017 at 12:26:32 AM UTC-7, Matt Yule-Bennett wrote:

You've got the right approach.

The WorkerContext has a `context_data` dict for carrying
request-contextual data like `session_id`, `locale` etc between calls. If
you put the `client_id` in there, it'll be available to all
DependencyProviders in the current service. It will also pass along between
service calls if your inter-service DependencyProviders and Entrypoints
pass it along. See my reply to your question here
<https://groups.google.com/forum/#!topic/nameko-dev/Jz2V0llSFJ0> for
more.

On Wednesday, April 19, 2017 at 2:29:52 AM UTC+1, di...@clearmetal.com >> wrote:

I have a use case where we have isolated databases for each client.
That means, when a request from a specific client comes in, I want to get
access to that client's specific database.

Let's say I have a database DependencyProvider (similar to
nameko_sqlalchemy), where the *setup *function instantiates all of my
connections to all of the client databases. I'm not entirely clear how I
can alter the worker_ctx in *get_dependency *so that I can return the
connection for a specific client. It seems like I somehow need to alter
worker_ctx so that I end up doing something like:

class Database(DependencyProvider):

    def setup(self):
        #Start all client connections

    def get_dependency(self, worker_ctx):
        client = worker_ctx['client_id']
        session_cls = sessionmaker(bind=self.connections[client])
        session = session_cls()
        self.session[worker_ctx] = session
        return session
       
Do you have any suggestions for how to do this?

Thanks!