[Catalyst] Catalyst::Component/Model Instances and Attributes per Request

Alejandro Imass alejandro.imass at gmail.com
Sat Jul 17 17:58:02 GMT 2010


On Fri, Jul 16, 2010 at 3:32 AM, Tomas Doran <bobtfish at bobtfish.net> wrote:
>
> On 15 Jul 2010, at 21:37, Alejandro Imass wrote:
>
>> On Mon, Jul 12, 2010 at 3:08 PM, Tomas Doran <bobtfish at bobtfish.net>
>> wrote:
>>>
>>> Each process is in a separate memory space if you're using FCGI or
>>> mod_perl
>>> or something, but it's not entirely certain (if you use
>>> Catalyst::Engine::PSGI and Corona (for example) then multiple requests
>>> can
>>> be in-flight and sharing the same logicial memory space application (they
>>> just have different instances of the request context).
>>>
>>
>> So we can assume mod_worker would certainly mix this data. The initial
>> quetion wasn't so stupid after all ;-)
>
> I believe from perl space it'll all still look like different processes, so
> no..
>

I am confused now. mod_worker will share the same code segment for
sure, and if you said earlier that in some scenarios where the code
segment is shared (i.e. two _threads_ using the same model instance)
the ACCEPT_CONTEXT call will override any global variables (i.e. Moose
object parameters) that were set by the previous the ACCEPT_CONTEXT
call. Or I understood wrong....

I'm pretty sure there is no sequential guarantee (a queue/stack) when
two controller threads use the same model instance, nor is the thread
implementation aware that it should create a separate data segment for
the second and beyond calls to ACCEPT_CONTEXT. I mean after all, being
an instance means that my model is just sitting there waiting for
events and ACCEPT_CONTEXT is just a hook so I can get info from the
current request. But wait, let me think out loud for a second:

Let's see. From my previous experience with Catalyst and mod_worker
(using Perl threads[1]). In each Apache process (i.e. an OS/Perl
process)  the code segment is shared amongst several threads (i.e. OS
LWP / Perl thread). So each Catalyst controller will share the code
segment but _most_ variables will be in a separate data segment, for
sure the my variables in each controller sub. Globals (i.e. Moose
attributes) I don't know enough about Moose and Catalyst internals to
say for sure. Do you? In the case that the controller's globals are
thread-safe then this must hold true as well for model instances. I
guess _that_ is the question.

>>> However doing what you suggest above will work for FCGI/mod_perl (or
>>> generally anything forked), although it's a bit icky - the instance of
>>> your
>>> Model lasts forever, and so bashing some of the instance data in each
>>> request works..
>>>
>>
>> Yes. I think for this particular case it's better for me to use a
>> class rather than an instance for this model.
>
> Wrong.
>
>> I'm suspecting that
>> instances are really to take advantage of caching DB connections and
>> things like that which I don't need or want for my particular model.
>
> Wrong.
>
> You want an instance. Always.
>
> If you just had a class for your then it would be impossible to load two
> copies of the same class into the same process space at any time. And you
> wouldn't _ever_ want to connect to the same database schema on two different
> servers at the same time...
>

My model is not for DB access, just to factorize code so that can be
used by many controllers. But it really doesn't matter, since I don't
understand why I could not load two classes and have completely
separate objects. They need not extend any Catalyst model classes,
just be plain Moose claasess and pass $c as an argument or attribute.

> Oh, no, wait - you would :)
>
> But that's fine, just inheriting from Catalyst::Model means that you have a
> COMPONENT method which will generate an instance... Although it's probably
> better to use ::Model::Adaptor or something, so that the COMPONENT instance
> creation logic and the actual implementation class aren't the same thing
> (and the actual class is decoupled from any Catalyst related logic).
>

Ok. I think that is part of the answer I'm looking for. But if you
could point me at the specific docs that explain this would be nice,
or do I necessarilly need to dive deep in the Catalyst code to see how
it actually works?

Thanks for your replies they've been very helpful.
Alex

> Cheers
> t0m
>

[1] The reason we need a multi-threaded implementation is because we
need to handle a large number of requests that just sit there waiting
for responses from slower down-stream servers, so to optimize RAM
specially in 64bits we need to share the code segment since we spawn
Apache processes/threads to the limit of the sevrer -1GB for the OS.
Catalyst has been used for this app even before the Moose re-write.
Leakage is inevitable (e.g. LWP on Linux and non-thread safe modules)
but there Apache corrections for this (e.g. MaxRequestsPerChild and
other tweaks).



More information about the Catalyst mailing list