Re: [Catalyst] One App, multiple databases

2008-11-20 Thread Jonathan Rockway
* On Wed, Nov 19 2008, Jose Luis Martinez wrote:

 sub ACCEPT_CONTEXT {
 my ($self, $c) = @_;

 my $user_db = $c-lookup_the_users_db();
 $self-{'dsn'} =~ s/#DATABASE#/$user_db/;

 return $self;
 }


I am really surprised that this works at all.  When do you actually ever
connect to the database with the DSN in $self-{dsn}?  (I am also
surprised that the DBIC version works.)

Anyway, mutating objects is wrong.  You should do things like this:

  package MyApp::Model::UsersDatabase;
  ...
  sub ACCEPT_CONTEXT {
  my ($self, $c) = @_;

  return $c-user-get_database($c-config-database_info);
  }

Then your user class should do something like:

  sub get_database {
  my ($self, $database_info) = @_;

  $self-database_connection($self-connect_to_database($database_info))
unless $self-has_database_connection;

  return $self-database_connection;
  }

(You can write cleaner code with a before method modifier, if you use
Moose.)

The idea is that each user has his own database connection, stored in
the user object, and Catalyst just returns the right thing when you say
$c-model('UsersDatabase').  This is much easier to reason about.

Regards,
Jonathan Rockway

--
print just = another = perl = hacker = if $,=$

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] One App, multiple databases

2008-11-20 Thread Jose Luis Martinez

Jonathan Rockway escribió:

* On Wed, Nov 19 2008, Jose Luis Martinez wrote:

sub ACCEPT_CONTEXT {
my ($self, $c) = @_;

my $user_db = $c-lookup_the_users_db();
$self-{'dsn'} =~ s/#DATABASE#/$user_db/;

return $self;
}



I am really surprised that this works at all.  When do you actually ever
connect to the database with the DSN in $self-{dsn}?  (I am also
surprised that the DBIC version works.)


It looks like the models don't connect to the database until it is first 
needed, so changing the properties with which they connect lets me get 
away with it. I think the fact that I'm working with app_server.pl -f 
helps me start each request without preestablished db connection.



Anyway, mutating objects is wrong.  You should do things like this:

  package MyApp::Model::UsersDatabase;
  ...
  sub ACCEPT_CONTEXT {
  my ($self, $c) = @_;

  return $c-user-get_database($c-config-database_info);
  }

Then your user class should do something like:

  sub get_database {
  my ($self, $database_info) = @_;

  $self-database_connection($self-connect_to_database($database_info))
unless $self-has_database_connection;

  return $self-database_connection;
  }
The idea is that each user has his own database connection, stored in
the user object, and Catalyst just returns the right thing when you say
$c-model('UsersDatabase').  This is much easier to reason about.


But I'll still have to change Model::DBI and/or Model::DBIC::Schema 
connection information on the fly... how should I do this in a clean way?


Regards,

Jose Luis Martinez
[EMAIL PROTECTED]

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] Duplicate entries with C::P::Session::Store::DBIC and MySQL - new findings

2008-11-20 Thread Sergio Salvi
On Fri, Sep 26, 2008 at 3:49 PM, Daniel Westermann-Clark [EMAIL PROTECTED] 
wrote:
 On 2008-08-26 09:47:59 +0200, Tobias Kremer wrote:
 a) Patch Catalyst::Plugin::Session::Store::DBIC to wrap the flash
functionality in a transaction (of course, this must be
configurable).

 I've released a new version which includes this functionality:

 0.07  Wed Sep 24 17:08:34 EDT 2008
- Code was silently truncating storage to MySQL, rendering the
  session unreadable. Patched to check DBIx::Class size from
  column_info (if available)
- Wrap find_or_create calls in a transaction to (hopefully)
  avoid issues with duplicate flash rows


Thanks for the patch, but unfortunately it does not solve the problem
with duplicate flash rows, because just wrapping find_or_create()
inside a txn_do() doesn't make it an atomic operation (because
find_or_create is simply not atomic, as pointed out in this thread).

The biggest problem is that the flash row gets deleted from the
database when flash is empty, so we're always doing insert  delete
and triggering the find_or_create problem.

I have a template to display error messages that is included by almost
every page, and these error messages are stored in flash. So every
request that does *not* have anything in flash and does not add
anything to flash, basically inserts the row (because my template did
something like FOREACH c.flash.my_error_messages), leaves the flash
empty and then decides to delete it. Make this happen too quickly and
you're hitting this problem very often (like we were on our
application).

I've modified Session.pm not to delete flash, even when it's empty.
The problem is gone, but it's a temporary hack I did to my local
version of Session.pm.

I still think the final solution (besides finding a way to make
find_or_create() atomic), is to store flash data the session row
(either on the same column of session or on a new, dedicated column).

I could try coming up with a patch + tests for this. Thoughts?

Thanks,
Sergio Salvi

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] Duplicate entries with C::P::Session::Store::DBIC and MySQL - new findings

2008-11-20 Thread Tobias Kremer

On 20.11.2008, at 21:16, Sergio Salvi wrote:

I still think the final solution (besides finding a way to make
find_or_create() atomic), is to store flash data the session row
(either on the same column of session or on a new, dedicated column).


Sergio++

FWIW, I rolled my own flash mechanism which does exactly that (store  
the flash value in the session) and haven't looked back since. I've  
seen about 3 duplicate entry errors in the last 3 months opposed to  
several hundreds a week with C::P::Session's flash method.


--Tobias


___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] One App, multiple databases

2008-11-20 Thread Tomas Doran


On 20 Nov 2008, at 14:51, Jose Luis Martinez wrote:


Jonathan Rockway escribió:

* On Wed, Nov 19 2008, Jose Luis Martinez wrote:

sub ACCEPT_CONTEXT {
my ($self, $c) = @_;

my $user_db = $c-lookup_the_users_db();
$self-{'dsn'} =~ s/#DATABASE#/$user_db/;

return $self;
}

I am really surprised that this works at all.  When do you  
actually ever

connect to the database with the DSN in $self-{dsn}?  (I am also
surprised that the DBIC version works.)


It looks like the models don't connect to the database until it is  
first needed, so changing the properties with which they connect  
lets me get away with it. I think the fact that I'm working with  
app_server.pl -f helps me start each request without preestablished  
db connection.



Anyway, mutating objects is wrong.  You should do things like this:
  package MyApp::Model::UsersDatabase;
  ...
  sub ACCEPT_CONTEXT {
  my ($self, $c) = @_;
  return $c-user-get_database($c-config-database_info);
  }
snip
The idea is that each user has his own database connection, stored in
the user object, and Catalyst just returns the right thing when  
you say

$c-model('UsersDatabase').  This is much easier to reason about.


But I'll still have to change Model::DBI and/or Model::DBIC::Schema  
connection information on the fly... how should I do this in a  
clean way?


No, you don't.

In your application code, instead of saying $c-model('DB')-dbh,  
with the example above, you would say $c-model('UsersDatabase'), and  
that would return you the dbh which the user object had generated.


You then work with it in exactly the same way as if you were using  
Catalyst::Model::DBI.


This means that you have to re-implement the connection logic of  
Catalst::Model::DBI in your user class. The only tricky bit is the  
stay_connected function, which is 16 lines long.


I don't think the code police will break down your door if you pinch  
this function verbatim. ;)


Cheers
t0m


___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/