[Dbix-class] Multi-tennant application/data and dbix-class

Thomas Klausner domm at cpan.org
Tue Jan 9 06:38:51 GMT 2018


Hi!

On Wed, Jan 03, 2018 at 10:07:49PM +0000, Andrew Beverley wrote:
 
> Yes, that's what I do.
> 
> > and thinking best approach will be to add logic to a resultset base
> > class or role to hook in forcing queries to restrict by tenant id
> 
> Yes, same as. I add an accessor in Schema.pm which contains tenant_id.
> Each time a request is made to the application, the very first thing I
> do is set $schema->tenant_id.
> 
> Then, I add a default resultset (also to Schema.pm), which adds this
> as a search automatically to all queries, if it exists in the table.

We did something similar for a long time, but for recent projects we 
stopped doing it like this. Mainly, because this concept causes a lot of 
hard-to-see action-at-a-distance. In the code that's actually loading 
something there is no hint that the search is limited to 'tenant_id'. 
You also have to make sure that somewhere early in your code path 
something sort of magically extract tenant_id from the environment (eg 
http request) and sets the schema attribute.

But the real killer was when we tried to run this in a non-forking, but 
'time-slicing' code (IO::Async).

As $schema->tenant_id is basically a global value, you really cannot use 
this approach when multiple "threads" try to write to and read from it 
at the same time.


Our solution was to extract the value from the env (eg in a 
controller action) and pass it explictly to the model:

  # SomeController
  
  sub some_action {
      my ($self, $req) = @_;
  
      my $customer   = $req->jwt_claims->{aud};
      my $some_param = $req->param('foo');
  
      $self->some_model->do_something($customer, $some_param);
  }
  
  # SomeModel
  
  sub do_something {
      my ($self, $customer_id, $foo) = @_;
  
      $self->resultset('SomeTable')->search_rs({
          customer => $customer_id,
  	  ...
      })
  }


Yes, this is a bit more work, and arguably a bit "dumber". But I think 
that the obviousness of what's going on in SomeModel->do_somthing is 
worth the effort.

Greeting,
domm

-- 
#!/usr/bin/perl                              http://domm.plix.at
for(ref bless{},just'another'perl'hacker){s-:+-$"-g&&print$_.$/}



More information about the DBIx-Class mailing list