a better way to recognize module changes

a better way to recognize module changes

am 11.09.2009 23:26:44 von Jonathan Swartz

I'm thinking about an improved solution to recognizing module changes
in a running server, without restarting the server.

These are the solutions I know about:

1) Apache2::Reload / Module::Reload

These check whether modules have changed on each request, and if so,
clear their symbols and reload them inside the process.

Problem: some modules fail to reload properly. Sometimes the failure
is intermittent, depending on the order of module loading and other
esoteric details. Moose and ORM modules seem particularly prone to
reload failures. For me, this level of unpredictability makes
*::Reload too frustrating to use.

2) Catalyst auto-restart

Catalyst has an engine (Catalyst::Engine::HTTP::Prefork::Restarter)
which forks off a "watcher" process that waits for your modules to
change. When they change, it restarts the server. The usual effect is
that, between the time you hit "save" in your editor and reload your
page, the server has restarted or at least begun restarting.

Problems: Doesn't work well if you make a few changes in a row; the
restart only captures your first change. Bad user experience if
there's an error in your module; you have to realize the server has
died, find the error message in some shell or log, and manually start
up the server again.

3) Perrin's MaxRequestsPerChild=1

Perrin recently alerted me to the MaxRequestsPerChild=1 technique.
That is, set MaxRequestsPerChild to 1, then load any potentially-
changing modules in the *child*, not the parent (obviously only for
development environments). Each request will hit a fresh child server,
which will load all of your potentially-changing modules anew.

This is the nicest solution I've seen so far. The only problem I can
see is its performance - each potentially-changing module has to be
loaded on each request. **

4) My idea: Combine 2 and 3

As in 3, load any potentially-changing modules in the child. Leave
MaxRequestsPerChild alone. As in 2, fork off a "watcher" process that
waits for your modules to change. When they change, kill all the
server's children explicitly.

The end result is that you get reasonable performance when your
modules don't change (e.g. when you are only futzing with templates),
but when modules do change, you should see the effects immediately.

This should be able to work with mod_perl, fastcgi, Net::Server, etc.,
as long as the parent server responds appropriately to the killing of
all its children (by launching new ones). Apache, at least, seems to
be ok with this.

What do people think? Is this worth codifying in a module, or does
something like this already exist?

Thanks for any feedback
Jon


** - You can try to load things only on demand, but often mod_perl
code is written without 'use' statements as it assumes everything is
loaded in the parent. You can also try to minimize the number of
potentially-changing modules, but then you run the risk of leaving
something off and having to adjust it and restart.

Re: a better way to recognize module changes

am 11.09.2009 23:52:41 von Perrin Harkins

On Fri, Sep 11, 2009 at 5:26 PM, Jonathan Swartz wrote:
> This is the nicest solution I've seen so far. The only problem I can see is
> its performance - each potentially-changing module has to be loaded on each
> request. **

How long does it take for you? I've run a lot of large mod_perl apps
this way and never seen it take more than 3 seconds to compile and
generate a page. Maybe this is only an issue with Moose? Or maybe
there's some expensive initialization that could be skipped in
development?

Anyway, another approach would be to set MaxClients to 1 and install
cleanup handler that kills the current process if it sees that any of
the watched modules have been changed. Then you don't need a separate
process.

- Perrin

Re: a better way to recognize module changes

am 12.09.2009 00:02:28 von Devin Teske

Maybe somebody can refute what I'm seeing, but as of mod_perl-2.0.4,
Apache2::Reload is gone (so you can remove that from your list of
options).
--
Devin

On Fri, 2009-09-11 at 14:26 -0700, Jonathan Swartz wrote:
> I'm thinking about an improved solution to recognizing module changes
> in a running server, without restarting the server.
>
> These are the solutions I know about:
>
> 1) Apache2::Reload / Module::Reload
>
> These check whether modules have changed on each request, and if so,
> clear their symbols and reload them inside the process.
>
> Problem: some modules fail to reload properly. Sometimes the failure
> is intermittent, depending on the order of module loading and other
> esoteric details. Moose and ORM modules seem particularly prone to
> reload failures. For me, this level of unpredictability makes
> *::Reload too frustrating to use.
>
> 2) Catalyst auto-restart
>
> Catalyst has an engine (Catalyst::Engine::HTTP::Prefork::Restarter)
> which forks off a "watcher" process that waits for your modules to
> change. When they change, it restarts the server. The usual effect is
> that, between the time you hit "save" in your editor and reload your
> page, the server has restarted or at least begun restarting.
>
> Problems: Doesn't work well if you make a few changes in a row; the
> restart only captures your first change. Bad user experience if
> there's an error in your module; you have to realize the server has
> died, find the error message in some shell or log, and manually start
> up the server again.
>
> 3) Perrin's MaxRequestsPerChild=1
>
> Perrin recently alerted me to the MaxRequestsPerChild=1 technique.
> That is, set MaxRequestsPerChild to 1, then load any potentially-
> changing modules in the *child*, not the parent (obviously only for
> development environments). Each request will hit a fresh child server,
> which will load all of your potentially-changing modules anew.
>
> This is the nicest solution I've seen so far. The only problem I can
> see is its performance - each potentially-changing module has to be
> loaded on each request. **
>
> 4) My idea: Combine 2 and 3
>
> As in 3, load any potentially-changing modules in the child. Leave
> MaxRequestsPerChild alone. As in 2, fork off a "watcher" process that
> waits for your modules to change. When they change, kill all the
> server's children explicitly.
>
> The end result is that you get reasonable performance when your
> modules don't change (e.g. when you are only futzing with templates),
> but when modules do change, you should see the effects immediately.
>
> This should be able to work with mod_perl, fastcgi, Net::Server, etc.,
> as long as the parent server responds appropriately to the killing of
> all its children (by launching new ones). Apache, at least, seems to
> be ok with this.
>
> What do people think? Is this worth codifying in a module, or does
> something like this already exist?
>
> Thanks for any feedback
> Jon
>
>
> ** - You can try to load things only on demand, but often mod_perl
> code is written without 'use' statements as it assumes everything is
> loaded in the parent. You can also try to minimize the number of
> potentially-changing modules, but then you run the risk of leaving
> something off and having to adjust it and restart.
>
--
Cheers,
Devin Teske

-> CONTACT INFORMATION <-
Field Engineer
Metavante Corporation
626-573-6040 Office
510-735-5650 Mobile
devin.teske@metavante.com

-> LEGAL DISCLAIMER <-
This message contains confidential and proprietary information
of the sender, and is intended only for the person(s) to whom it
is addressed. Any use, distribution, copying or disclosure by any
other person is strictly prohibited. If you have received this
message in error, please notify the e-mail sender immediately,
and delete the original message without making a copy.

-> END TRANSMISSION <-

Re: a better way to recognize module changes

am 12.09.2009 00:11:21 von Fred Moyer

On Fri, Sep 11, 2009 at 3:02 PM, Devin Teske wrote:
> Maybe somebody can refute what I'm seeing, but as of mod_perl-2.0.4,
> Apache2::Reload is gone (so you can remove that from your list of
> options).

It was not bundled with 2.0.4 but is available on CPAN:

http://search.cpan.org/dist/Apache-Reload

It will be bundled again with 2.0.5. There was a discussion on the
dev list about how to manage perl based Apache2?::* modules with
mod_perl core releases and the specific version control procedures to
accomplish this in a pain free manner.

> --
> Devin
>
> On Fri, 2009-09-11 at 14:26 -0700, Jonathan Swartz wrote:
>> I'm thinking about an improved solution to recognizing module changes
>> in a running server, without restarting the server.
>>
>> These are the solutions I know about:
>>
>> 1) Apache2::Reload / Module::Reload
>>
>> These check whether modules have changed on each request, and if so,
>> clear their symbols and reload them inside the process.
>>
>> Problem: some modules fail to reload properly. Sometimes the failure
>> is intermittent, depending on the order of module loading and other
>> esoteric details. Moose and ORM modules seem particularly prone to
>> reload failures. For me, this level of unpredictability makes
>> *::Reload too frustrating to use.
>>
>> 2) Catalyst auto-restart
>>
>> Catalyst has an engine (Catalyst::Engine::HTTP::Prefork::Restarter)
>> which forks off a "watcher" process that waits for your modules to
>> change. When they change, it restarts the server. The usual effect is
>> that, between the time you hit "save" in your editor and reload your
>> page, the server has restarted or at least begun restarting.
>>
>> Problems: Doesn't work well if you make a few changes in a row; the
>> restart only captures your first change. Bad user experience if
>> there's an error in your module; you have to realize the server has
>> died, find the error message in some shell or log, and manually start
>> up the server again.
>>
>> 3) Perrin's MaxRequestsPerChild=3D1
>>
>> Perrin recently alerted me to the MaxRequestsPerChild=3D1 technique.
>> That is, set MaxRequestsPerChild to 1, then load any potentially-
>> changing modules in the *child*, not the parent (obviously only for
>> development environments). Each request will hit a fresh child server,
>> which will load all of your potentially-changing modules anew.
>>
>> This is the nicest solution I've seen so far. The only problem I can
>> see is its performance - each potentially-changing module has to be
>> loaded on each request. **
>>
>> 4) My idea: Combine 2 and 3
>>
>> As in 3, load any potentially-changing modules in the child. Leave
>> MaxRequestsPerChild alone. As in 2, fork off a "watcher" process that
>> waits for your modules to change. When they change, kill all the
>> server's children explicitly.
>>
>> The end result is that you get reasonable performance when your
>> modules don't change (e.g. when you are only futzing with templates),
>> but when modules do change, you should see the effects immediately.
>>
>> This should be able to work with mod_perl, fastcgi, Net::Server, etc.,
>> as long as the parent server responds appropriately to the killing of
>> all its children (by launching new ones). Apache, at least, seems to
>> be ok with this.
>>
>> What do people think? Is this worth codifying in a module, or does
>> something like this already exist?
>>
>> Thanks for any feedback
>> Jon
>>
>>
>> ** - You can try to load things only on demand, but often mod_perl
>> code is written without 'use' statements as it assumes everything is
>> loaded in the parent. You can also try to minimize the number of
>> potentially-changing modules, but then you run the risk of leaving
>> something off and having to adjust it and restart.
>>
> --
> Cheers,
> Devin Teske
>
> -> CONTACT INFORMATION <-
> Field Engineer
> Metavante Corporation
> 626-573-6040 Office
> 510-735-5650 Mobile
> devin.teske@metavante.com
>
> -> LEGAL DISCLAIMER <-
> This message =A0contains confidential =A0and proprietary =A0information
> of the sender, =A0and is intended only for the person(s) to whom it
> is addressed. Any use, distribution, copying or disclosure by any
> other person =A0is strictly prohibited. =A0If you have =A0received this
> message in error, =A0please notify =A0the e-mail sender =A0immediately,
> and delete the original message without making a copy.
>
> -> END TRANSMISSION <-
>
>

Re: a better way to recognize module changes

am 12.09.2009 00:11:34 von Jonathan Swartz

It seems like it's available separately in Apache-Reload distribution: http://cpan.uwinnipeg.ca/dist/Apache-Reload

But it's already pretty much a straw-man option for me. :)

Jon

On Sep 11, 2009, at 3:02 PM, Devin Teske wrote:

> Maybe somebody can refute what I'm seeing, but as of mod_perl-2.0.4,
> Apache2::Reload is gone (so you can remove that from your list of
> options).
> --
> Devin
>
> On Fri, 2009-09-11 at 14:26 -0700, Jonathan Swartz wrote:
>> I'm thinking about an improved solution to recognizing module changes
>> in a running server, without restarting the server.
>>
>> These are the solutions I know about:
>>
>> 1) Apache2::Reload / Module::Reload
>>
>> These check whether modules have changed on each request, and if so,
>> clear their symbols and reload them inside the process.
>>
>> Problem: some modules fail to reload properly. Sometimes the failure
>> is intermittent, depending on the order of module loading and other
>> esoteric details. Moose and ORM modules seem particularly prone to
>> reload failures. For me, this level of unpredictability makes
>> *::Reload too frustrating to use.
>>
>> 2) Catalyst auto-restart
>>
>> Catalyst has an engine (Catalyst::Engine::HTTP::Prefork::Restarter)
>> which forks off a "watcher" process that waits for your modules to
>> change. When they change, it restarts the server. The usual effect is
>> that, between the time you hit "save" in your editor and reload your
>> page, the server has restarted or at least begun restarting.
>>
>> Problems: Doesn't work well if you make a few changes in a row; the
>> restart only captures your first change. Bad user experience if
>> there's an error in your module; you have to realize the server has
>> died, find the error message in some shell or log, and manually start
>> up the server again.
>>
>> 3) Perrin's MaxRequestsPerChild=1
>>
>> Perrin recently alerted me to the MaxRequestsPerChild=1 technique.
>> That is, set MaxRequestsPerChild to 1, then load any potentially-
>> changing modules in the *child*, not the parent (obviously only for
>> development environments). Each request will hit a fresh child
>> server,
>> which will load all of your potentially-changing modules anew.
>>
>> This is the nicest solution I've seen so far. The only problem I can
>> see is its performance - each potentially-changing module has to be
>> loaded on each request. **
>>
>> 4) My idea: Combine 2 and 3
>>
>> As in 3, load any potentially-changing modules in the child. Leave
>> MaxRequestsPerChild alone. As in 2, fork off a "watcher" process that
>> waits for your modules to change. When they change, kill all the
>> server's children explicitly.
>>
>> The end result is that you get reasonable performance when your
>> modules don't change (e.g. when you are only futzing with templates),
>> but when modules do change, you should see the effects immediately.
>>
>> This should be able to work with mod_perl, fastcgi, Net::Server,
>> etc.,
>> as long as the parent server responds appropriately to the killing of
>> all its children (by launching new ones). Apache, at least, seems to
>> be ok with this.
>>
>> What do people think? Is this worth codifying in a module, or does
>> something like this already exist?
>>
>> Thanks for any feedback
>> Jon
>>
>>
>> ** - You can try to load things only on demand, but often mod_perl
>> code is written without 'use' statements as it assumes everything is
>> loaded in the parent. You can also try to minimize the number of
>> potentially-changing modules, but then you run the risk of leaving
>> something off and having to adjust it and restart.
>>
> --
> Cheers,
> Devin Teske
>
> -> CONTACT INFORMATION <-
> Field Engineer
> Metavante Corporation
> 626-573-6040 Office
> 510-735-5650 Mobile
> devin.teske@metavante.com
>
> -> LEGAL DISCLAIMER <-
> This message contains confidential and proprietary information
> of the sender, and is intended only for the person(s) to whom it
> is addressed. Any use, distribution, copying or disclosure by any
> other person is strictly prohibited. If you have received this
> message in error, please notify the e-mail sender immediately,
> and delete the original message without making a copy.
>
> -> END TRANSMISSION <-
>

Re: a better way to recognize module changes

am 12.09.2009 00:18:03 von Jonathan Swartz

On Sep 11, 2009, at 2:52 PM, Perrin Harkins wrote:

> On Fri, Sep 11, 2009 at 5:26 PM, Jonathan Swartz
> wrote:
>> This is the nicest solution I've seen so far. The only problem I
>> can see is
>> its performance - each potentially-changing module has to be loaded
>> on each
>> request. **
>
> How long does it take for you? I've run a lot of large mod_perl apps
> this way and never seen it take more than 3 seconds to compile and
> generate a page. Maybe this is only an issue with Moose? Or maybe
> there's some expensive initialization that could be skipped in
> development?
>

It can take a few seconds to load all our modules (sans the CPAN
modules they use). Perhaps I'm particularly sensitive to development
environment efficiency. But if we could codify a relatively simple
solution that eliminates those seconds, why not?

> Anyway, another approach would be to set MaxClients to 1 and install
> cleanup handler that kills the current process if it sees that any of
> the watched modules have been changed. Then you don't need a separate
> process.
>

But if you change a module, wouldn't your first subsequent request hit
the 'old' code? That's the benefit of an independent watcher, it'll
operate in the time between when you've changed your module and when
you hit the server again.

Jon

Re: a better way to recognize module changes

am 12.09.2009 00:20:11 von Devin Teske

Was there any particular reason that it wasn't packaged with 2.0.4?
(meaning, can I just supplant the one from 2.0.3... or was it removed
only to be re-added after being patched for some particular purpose?)
--
Devin


On Fri, 2009-09-11 at 15:11 -0700, Fred Moyer wrote:
> On Fri, Sep 11, 2009 at 3:02 PM, Devin Teske wrote:
> > Maybe somebody can refute what I'm seeing, but as of mod_perl-2.0.4,
> > Apache2::Reload is gone (so you can remove that from your list of
> > options).
>
> It was not bundled with 2.0.4 but is available on CPAN:
>
> http://search.cpan.org/dist/Apache-Reload
>
> It will be bundled again with 2.0.5. There was a discussion on the
> dev list about how to manage perl based Apache2?::* modules with
> mod_perl core releases and the specific version control procedures to
> accomplish this in a pain free manner.
>
> > --
> > Devin
> >
> > On Fri, 2009-09-11 at 14:26 -0700, Jonathan Swartz wrote:
> >> I'm thinking about an improved solution to recognizing module changes
> >> in a running server, without restarting the server.
> >>
> >> These are the solutions I know about:
> >>
> >> 1) Apache2::Reload / Module::Reload
> >>
> >> These check whether modules have changed on each request, and if so,
> >> clear their symbols and reload them inside the process.
> >>
> >> Problem: some modules fail to reload properly. Sometimes the failure
> >> is intermittent, depending on the order of module loading and other
> >> esoteric details. Moose and ORM modules seem particularly prone to
> >> reload failures. For me, this level of unpredictability makes
> >> *::Reload too frustrating to use.
> >>
> >> 2) Catalyst auto-restart
> >>
> >> Catalyst has an engine (Catalyst::Engine::HTTP::Prefork::Restarter)
> >> which forks off a "watcher" process that waits for your modules to
> >> change. When they change, it restarts the server. The usual effect is
> >> that, between the time you hit "save" in your editor and reload your
> >> page, the server has restarted or at least begun restarting.
> >>
> >> Problems: Doesn't work well if you make a few changes in a row; the
> >> restart only captures your first change. Bad user experience if
> >> there's an error in your module; you have to realize the server has
> >> died, find the error message in some shell or log, and manually start
> >> up the server again.
> >>
> >> 3) Perrin's MaxRequestsPerChild=1
> >>
> >> Perrin recently alerted me to the MaxRequestsPerChild=1 technique.
> >> That is, set MaxRequestsPerChild to 1, then load any potentially-
> >> changing modules in the *child*, not the parent (obviously only for
> >> development environments). Each request will hit a fresh child server,
> >> which will load all of your potentially-changing modules anew.
> >>
> >> This is the nicest solution I've seen so far. The only problem I can
> >> see is its performance - each potentially-changing module has to be
> >> loaded on each request. **
> >>
> >> 4) My idea: Combine 2 and 3
> >>
> >> As in 3, load any potentially-changing modules in the child. Leave
> >> MaxRequestsPerChild alone. As in 2, fork off a "watcher" process that
> >> waits for your modules to change. When they change, kill all the
> >> server's children explicitly.
> >>
> >> The end result is that you get reasonable performance when your
> >> modules don't change (e.g. when you are only futzing with templates),
> >> but when modules do change, you should see the effects immediately.
> >>
> >> This should be able to work with mod_perl, fastcgi, Net::Server, etc.,
> >> as long as the parent server responds appropriately to the killing of
> >> all its children (by launching new ones). Apache, at least, seems to
> >> be ok with this.
> >>
> >> What do people think? Is this worth codifying in a module, or does
> >> something like this already exist?
> >>
> >> Thanks for any feedback
> >> Jon
> >>
> >>
> >> ** - You can try to load things only on demand, but often mod_perl
> >> code is written without 'use' statements as it assumes everything is
> >> loaded in the parent. You can also try to minimize the number of
> >> potentially-changing modules, but then you run the risk of leaving
> >> something off and having to adjust it and restart.
> >>
> > --
> > Cheers,
> > Devin Teske
> >
> > -> CONTACT INFORMATION <-
> > Field Engineer
> > Metavante Corporation
> > 626-573-6040 Office
> > 510-735-5650 Mobile
> > devin.teske@metavante.com
> >
> > -> LEGAL DISCLAIMER <-
> > This message contains confidential and proprietary information
> > of the sender, and is intended only for the person(s) to whom it
> > is addressed. Any use, distribution, copying or disclosure by any
> > other person is strictly prohibited. If you have received this
> > message in error, please notify the e-mail sender immediately,
> > and delete the original message without making a copy.
> >
> > -> END TRANSMISSION <-
> >
> >
--
Cheers,
Devin Teske

-> CONTACT INFORMATION <-
Field Engineer
Metavante Corporation
626-573-6040 Office
510-735-5650 Mobile
devin.teske@metavante.com

-> LEGAL DISCLAIMER <-
This message contains confidential and proprietary information
of the sender, and is intended only for the person(s) to whom it
is addressed. Any use, distribution, copying or disclosure by any
other person is strictly prohibited. If you have received this
message in error, please notify the e-mail sender immediately,
and delete the original message without making a copy.

-> END TRANSMISSION <-

Re: a better way to recognize module changes

am 12.09.2009 00:22:51 von Jonathan Swartz

Incidentally Perrin - how do you come up with the list of vendor (i.e.
not your project's) modules to load in the parent? Do you just load a
page, look at %INC, and then subtract out your personal modules? Do
you have to do this every so often to catch new vendor modules that
have snuck in as dependencies?

On Sep 11, 2009, at 2:52 PM, Perrin Harkins wrote:

> On Fri, Sep 11, 2009 at 5:26 PM, Jonathan Swartz
> wrote:
>> This is the nicest solution I've seen so far. The only problem I
>> can see is
>> its performance - each potentially-changing module has to be loaded
>> on each
>> request. **
>
> How long does it take for you? I've run a lot of large mod_perl apps
> this way and never seen it take more than 3 seconds to compile and
> generate a page. Maybe this is only an issue with Moose? Or maybe
> there's some expensive initialization that could be skipped in
> development?
>
> Anyway, another approach would be to set MaxClients to 1 and install
> cleanup handler that kills the current process if it sees that any of
> the watched modules have been changed. Then you don't need a separate
> process.
>
> - Perrin

Re: a better way to recognize module changes

am 12.09.2009 00:23:06 von Fred Moyer

On Fri, Sep 11, 2009 at 3:20 PM, Devin Teske wrote:
> Was there any particular reason that it wasn't packaged with 2.0.4?
> (meaning, can I just supplant the one from 2.0.3... or was it removed
> only to be re-added after being patched for some particular purpose?)

It was not included because of a miscommunication when releasing 0.10.

You can install 0.10 from CPAN and should be fine.

The conclusions after the post mortem were that the latest stable
versions of Apache::* modules should be included with mod_perl core
releases, but later versions of those modules should be easily
upgradeable from CPAN.

> --
> Devin
>
>
> On Fri, 2009-09-11 at 15:11 -0700, Fred Moyer wrote:
>> On Fri, Sep 11, 2009 at 3:02 PM, Devin Teske wrote:
>> > Maybe somebody can refute what I'm seeing, but as of mod_perl-2.0.4,
>> > Apache2::Reload is gone (so you can remove that from your list of
>> > options).
>>
>> It was not bundled with 2.0.4 but is available on CPAN:
>>
>> http://search.cpan.org/dist/Apache-Reload
>>
>> It will be bundled again with 2.0.5. =A0There was a discussion on the
>> dev list about how to manage perl based Apache2?::* modules with
>> mod_perl core releases and the specific version control procedures to
>> accomplish this in a pain free manner.
>>
>> > --
>> > Devin
>> >
>> > On Fri, 2009-09-11 at 14:26 -0700, Jonathan Swartz wrote:
>> >> I'm thinking about an improved solution to recognizing module changes
>> >> in a running server, without restarting the server.
>> >>
>> >> These are the solutions I know about:
>> >>
>> >> 1) Apache2::Reload / Module::Reload
>> >>
>> >> These check whether modules have changed on each request, and if so,
>> >> clear their symbols and reload them inside the process.
>> >>
>> >> Problem: some modules fail to reload properly. Sometimes the failure
>> >> is intermittent, depending on the order of module loading and other
>> >> esoteric details. Moose and ORM modules seem particularly prone to
>> >> reload failures. For me, this level of unpredictability makes
>> >> *::Reload too frustrating to use.
>> >>
>> >> 2) Catalyst auto-restart
>> >>
>> >> Catalyst has an engine (Catalyst::Engine::HTTP::Prefork::Restarter)
>> >> which forks off a "watcher" process that waits for your modules to
>> >> change. When they change, it restarts the server. The usual effect is
>> >> that, between the time you hit "save" in your editor and reload your
>> >> page, the server has restarted or at least begun restarting.
>> >>
>> >> Problems: Doesn't work well if you make a few changes in a row; the
>> >> restart only captures your first change. Bad user experience if
>> >> there's an error in your module; you have to realize the server has
>> >> died, find the error message in some shell or log, and manually start
>> >> up the server again.
>> >>
>> >> 3) Perrin's MaxRequestsPerChild=3D1
>> >>
>> >> Perrin recently alerted me to the MaxRequestsPerChild=3D1 technique.
>> >> That is, set MaxRequestsPerChild to 1, then load any potentially-
>> >> changing modules in the *child*, not the parent (obviously only for
>> >> development environments). Each request will hit a fresh child server=
,
>> >> which will load all of your potentially-changing modules anew.
>> >>
>> >> This is the nicest solution I've seen so far. The only problem I can
>> >> see is its performance - each potentially-changing module has to be
>> >> loaded on each request. **
>> >>
>> >> 4) My idea: Combine 2 and 3
>> >>
>> >> As in 3, load any potentially-changing modules in the child. Leave
>> >> MaxRequestsPerChild alone. As in 2, fork off a "watcher" process that
>> >> waits for your modules to change. When they change, kill all the
>> >> server's children explicitly.
>> >>
>> >> The end result is that you get reasonable performance when your
>> >> modules don't change (e.g. when you are only futzing with templates),
>> >> but when modules do change, you should see the effects immediately.
>> >>
>> >> This should be able to work with mod_perl, fastcgi, Net::Server, etc.=
,
>> >> as long as the parent server responds appropriately to the killing of
>> >> all its children (by launching new ones). Apache, at least, seems to
>> >> be ok with this.
>> >>
>> >> What do people think? Is this worth codifying in a module, or does
>> >> something like this already exist?
>> >>
>> >> Thanks for any feedback
>> >> Jon
>> >>
>> >>
>> >> ** - You can try to load things only on demand, but often mod_perl
>> >> code is written without 'use' statements as it assumes everything is
>> >> loaded in the parent. You can also try to minimize the number of
>> >> potentially-changing modules, but then you run the risk of leaving
>> >> something off and having to adjust it and restart.
>> >>
>> > --
>> > Cheers,
>> > Devin Teske
>> >
>> > -> CONTACT INFORMATION <-
>> > Field Engineer
>> > Metavante Corporation
>> > 626-573-6040 Office
>> > 510-735-5650 Mobile
>> > devin.teske@metavante.com
>> >
>> > -> LEGAL DISCLAIMER <-
>> > This message =A0contains confidential =A0and proprietary =A0informatio=
n
>> > of the sender, =A0and is intended only for the person(s) to whom it
>> > is addressed. Any use, distribution, copying or disclosure by any
>> > other person =A0is strictly prohibited. =A0If you have =A0received thi=
s
>> > message in error, =A0please notify =A0the e-mail sender =A0immediately=
,
>> > and delete the original message without making a copy.
>> >
>> > -> END TRANSMISSION <-
>> >
>> >
> --
> Cheers,
> Devin Teske
>
> -> CONTACT INFORMATION <-
> Field Engineer
> Metavante Corporation
> 626-573-6040 Office
> 510-735-5650 Mobile
> devin.teske@metavante.com
>
> -> LEGAL DISCLAIMER <-
> This message =A0contains confidential =A0and proprietary =A0information
> of the sender, =A0and is intended only for the person(s) to whom it
> is addressed. Any use, distribution, copying or disclosure by any
> other person =A0is strictly prohibited. =A0If you have =A0received this
> message in error, =A0please notify =A0the e-mail sender =A0immediately,
> and delete the original message without making a copy.
>
> -> END TRANSMISSION <-
>
>

Re: a better way to recognize module changes

am 12.09.2009 00:26:19 von Fred Moyer

On Fri, Sep 11, 2009 at 3:11 PM, Jonathan Swartz wrote:
> It seems like it's available separately in Apache-Reload distribution:
> http://cpan.uwinnipeg.ca/dist/Apache-Reload
>
> But it's already pretty much a straw-man option for me. :)

>>> Problem: some modules fail to reload properly. Sometimes the failure
>>> is intermittent, depending on the order of module loading and other
>>> esoteric details. Moose and ORM modules seem particularly prone to
>>> reload failures. For me, this level of unpredictability makes
>>> *::Reload too frustrating to use.

I've run into issues with reloading ORM based modules such as when I
change my DBIx::Class based schema. I get an inconsistent hierarchy
error from Class::C3. So in those cases a server restart is required.

However, if your model layer is abstracted from mod_perl, you should
be able to develop against your model layer using tests, and then
install your upgraded model and restart Apache then. The behavior
where I encounter problems reloading changes to ORM modules has
enforced a good separation of model (ORM) and controller( mod_perl )
code in my application.


>

> Jon
>
> On Sep 11, 2009, at 3:02 PM, Devin Teske wrote:
>
>> Maybe somebody can refute what I'm seeing, but as of mod_perl-2.0.4,
>> Apache2::Reload is gone (so you can remove that from your list of
>> options).
>> --
>> Devin
>>
>> On Fri, 2009-09-11 at 14:26 -0700, Jonathan Swartz wrote:
>>>
>>> I'm thinking about an improved solution to recognizing module changes
>>> in a running server, without restarting the server.
>>>
>>> These are the solutions I know about:
>>>
>>> 1) Apache2::Reload / Module::Reload
>>>
>>> These check whether modules have changed on each request, and if so,
>>> clear their symbols and reload them inside the process.
>>>
>>> Problem: some modules fail to reload properly. Sometimes the failure
>>> is intermittent, depending on the order of module loading and other
>>> esoteric details. Moose and ORM modules seem particularly prone to
>>> reload failures. For me, this level of unpredictability makes
>>> *::Reload too frustrating to use.
>>>
>>> 2) Catalyst auto-restart
>>>
>>> Catalyst has an engine (Catalyst::Engine::HTTP::Prefork::Restarter)
>>> which forks off a "watcher" process that waits for your modules to
>>> change. When they change, it restarts the server. The usual effect is
>>> that, between the time you hit "save" in your editor and reload your
>>> page, the server has restarted or at least begun restarting.
>>>
>>> Problems: Doesn't work well if you make a few changes in a row; the
>>> restart only captures your first change. Bad user experience if
>>> there's an error in your module; you have to realize the server has
>>> died, find the error message in some shell or log, and manually start
>>> up the server again.
>>>
>>> 3) Perrin's MaxRequestsPerChild=3D1
>>>
>>> Perrin recently alerted me to the MaxRequestsPerChild=3D1 technique.
>>> That is, set MaxRequestsPerChild to 1, then load any potentially-
>>> changing modules in the *child*, not the parent (obviously only for
>>> development environments). Each request will hit a fresh child server,
>>> which will load all of your potentially-changing modules anew.
>>>
>>> This is the nicest solution I've seen so far. The only problem I can
>>> see is its performance - each potentially-changing module has to be
>>> loaded on each request. **
>>>
>>> 4) My idea: Combine 2 and 3
>>>
>>> As in 3, load any potentially-changing modules in the child. Leave
>>> MaxRequestsPerChild alone. As in 2, fork off a "watcher" process that
>>> waits for your modules to change. When they change, kill all the
>>> server's children explicitly.
>>>
>>> The end result is that you get reasonable performance when your
>>> modules don't change (e.g. when you are only futzing with templates),
>>> but when modules do change, you should see the effects immediately.
>>>
>>> This should be able to work with mod_perl, fastcgi, Net::Server, etc.,
>>> as long as the parent server responds appropriately to the killing of
>>> all its children (by launching new ones). Apache, at least, seems to
>>> be ok with this.
>>>
>>> What do people think? Is this worth codifying in a module, or does
>>> something like this already exist?
>>>
>>> Thanks for any feedback
>>> Jon
>>>
>>>
>>> ** - You can try to load things only on demand, but often mod_perl
>>> code is written without 'use' statements as it assumes everything is
>>> loaded in the parent. You can also try to minimize the number of
>>> potentially-changing modules, but then you run the risk of leaving
>>> something off and having to adjust it and restart.
>>>
>> --
>> Cheers,
>> Devin Teske
>>
>> -> CONTACT INFORMATION <-
>> Field Engineer
>> Metavante Corporation
>> 626-573-6040 Office
>> 510-735-5650 Mobile
>> devin.teske@metavante.com
>>
>> -> LEGAL DISCLAIMER <-
>> This message =A0contains confidential =A0and proprietary =A0information
>> of the sender, =A0and is intended only for the person(s) to whom it
>> is addressed. Any use, distribution, copying or disclosure by any
>> other person =A0is strictly prohibited. =A0If you have =A0received this
>> message in error, =A0please notify =A0the e-mail sender =A0immediately,
>> and delete the original message without making a copy.
>>
>> -> END TRANSMISSION <-
>>
>
>

Re: a better way to recognize module changes

am 12.09.2009 00:37:14 von Jonathan Swartz

> On Fri, Sep 11, 2009 at 3:11 PM, Jonathan Swartz
> wrote:
>> It seems like it's available separately in Apache-Reload
>> distribution:
>> http://cpan.uwinnipeg.ca/dist/Apache-Reload
>>
>> But it's already pretty much a straw-man option for me. :)
>
>>>> Problem: some modules fail to reload properly. Sometimes the
>>>> failure
>>>> is intermittent, depending on the order of module loading and other
>>>> esoteric details. Moose and ORM modules seem particularly prone to
>>>> reload failures. For me, this level of unpredictability makes
>>>> *::Reload too frustrating to use.
>
> I've run into issues with reloading ORM based modules such as when I
> change my DBIx::Class based schema. I get an inconsistent hierarchy
> error from Class::C3. So in those cases a server restart is required.
>
> However, if your model layer is abstracted from mod_perl, you should
> be able to develop against your model layer using tests, and then
> install your upgraded model and restart Apache then. The behavior
> where I encounter problems reloading changes to ORM modules has
> enforced a good separation of model (ORM) and controller( mod_perl )
> code in my application.

I'm all for TDD, to be sure, but in practice not everything -
especially with controller and view-specific modules - is going to be
developed in this way.

I've often exhorted Mason developers to move things out of components
into modules, but a real objection to that has been the server restart
cost, and I've never had a good answer for it. Mason components (like
TT templates, etc.) can pretty much always be reloaded without
restart, which I expect is one reason why so much code ends up there.

Jon

Re: a better way to recognize module changes

am 12.09.2009 00:53:23 von Fred Moyer

On Fri, Sep 11, 2009 at 3:37 PM, Jonathan Swartz wrote:
>
>> On Fri, Sep 11, 2009 at 3:11 PM, Jonathan Swartz wrot=
e:
>>>
>>> It seems like it's available separately in Apache-Reload distribution:
>>> http://cpan.uwinnipeg.ca/dist/Apache-Reload
>>>
>>> But it's already pretty much a straw-man option for me. :)
>>
>>>>> Problem: some modules fail to reload properly. Sometimes the failure
>>>>> is intermittent, depending on the order of module loading and other
>>>>> esoteric details. Moose and ORM modules seem particularly prone to
>>>>> reload failures. For me, this level of unpredictability makes
>>>>> *::Reload too frustrating to use.
>>
>> I've run into issues with reloading ORM based modules such as when I
>> change my DBIx::Class based schema. =A0I get an inconsistent hierarchy
>> error from Class::C3. =A0So in those cases a server restart is required.
>>
>> However, if your model layer is abstracted from mod_perl, you should
>> be able to develop against your model layer using tests, and then
>> install your upgraded model and restart Apache then. =A0The behavior
>> where I encounter problems reloading changes to ORM modules has
>> enforced a good separation of model (ORM) and controller( mod_perl )
>> code in my application.
>
> I'm all for TDD, to be sure, but in practice not everything - especially
> with controller and view-specific modules - is going to be developed in t=
his
> way.
>
> I've often exhorted Mason developers to move things out of components int=
o
> modules, but a real objection to that has been the server restart cost, a=
nd
> I've never had a good answer for it. Mason components (like TT templates,
> etc.) can pretty much always be reloaded without restart, which I expect =
is
> one reason why so much code ends up there.

That makes a lot of sense.

Only thing I could suggest would be to exclude your Moose based
modules from Apache::Reload reload list if they are causing problems.

Although, if there was a way to kill off user owned httpd processes
when a code change was made, you could extend Apache::Reload to have
certain modules cause httpd recycling vs code reloading.

Maybe something like:

PerlSetVar ReloadAll On

PerlSetVar ReloadHttpds My::Moose

So that modules in ReloadHttpds terminates existing user httpd
processes and causes the server to fork off new httpd children.

>
> Jon
>
>

Re: a better way to recognize module changes

am 12.09.2009 00:57:00 von Jonathan Swartz

On Sep 11, 2009, at 3:53 PM, Fred Moyer wrote:

> On Fri, Sep 11, 2009 at 3:37 PM, Jonathan Swartz
> wrote:
>>
>>> On Fri, Sep 11, 2009 at 3:11 PM, Jonathan Swartz
>>> wrote:
>>>>
>>>> It seems like it's available separately in Apache-Reload
>>>> distribution:
>>>> http://cpan.uwinnipeg.ca/dist/Apache-Reload
>>>>
>>>> But it's already pretty much a straw-man option for me. :)
>>>
>>>>>> Problem: some modules fail to reload properly. Sometimes the
>>>>>> failure
>>>>>> is intermittent, depending on the order of module loading and
>>>>>> other
>>>>>> esoteric details. Moose and ORM modules seem particularly prone
>>>>>> to
>>>>>> reload failures. For me, this level of unpredictability makes
>>>>>> *::Reload too frustrating to use.
>>>
>>> I've run into issues with reloading ORM based modules such as when I
>>> change my DBIx::Class based schema. I get an inconsistent hierarchy
>>> error from Class::C3. So in those cases a server restart is
>>> required.
>>>
>>> However, if your model layer is abstracted from mod_perl, you should
>>> be able to develop against your model layer using tests, and then
>>> install your upgraded model and restart Apache then. The behavior
>>> where I encounter problems reloading changes to ORM modules has
>>> enforced a good separation of model (ORM) and controller( mod_perl )
>>> code in my application.
>>
>> I'm all for TDD, to be sure, but in practice not everything -
>> especially
>> with controller and view-specific modules - is going to be
>> developed in this
>> way.
>>
>> I've often exhorted Mason developers to move things out of
>> components into
>> modules, but a real objection to that has been the server restart
>> cost, and
>> I've never had a good answer for it. Mason components (like TT
>> templates,
>> etc.) can pretty much always be reloaded without restart, which I
>> expect is
>> one reason why so much code ends up there.
>
> That makes a lot of sense.
>
> Only thing I could suggest would be to exclude your Moose based
> modules from Apache::Reload reload list if they are causing problems.
>
> Although, if there was a way to kill off user owned httpd processes
> when a code change was made, you could extend Apache::Reload to have
> certain modules cause httpd recycling vs code reloading.
>
> Maybe something like:
>
> PerlSetVar ReloadAll On
>
> PerlSetVar ReloadHttpds My::Moose
>
> So that modules in ReloadHttpds terminates existing user httpd
> processes and causes the server to fork off new httpd children.

But again, if Apache::Reload runs as part of the child process itself,
how can it implement ReloadHttpds effectively? It would have to kill
itself off, which would mean your first request would generate an
error - not a good user experience.

Re: a better way to recognize module changes

am 12.09.2009 01:10:27 von John Siracusa

On 9/11/09 6:57 PM, Jonathan Swartz wrote:
>> PerlSetVar ReloadAll On
>>
>> PerlSetVar ReloadHttpds My::Moose
>>
>> So that modules in ReloadHttpds terminates existing user httpd
>> processes and causes the server to fork off new httpd children.
>
> But again, if Apache::Reload runs as part of the child process itself,
> how can it implement ReloadHttpds effectively? It would have to kill
> itself off, which would mean your first request would generate an
> error - not a good user experience.

The last thing I did in this area looked something like this:

PerlCleanupHandler My::WebApp::Restarter
PerlSetVar WatcherInterval 60
PerlSetVar WatcherCompileCheck 1

where all the handler did was fork off a watcher process if one didn't
already exist. The watcher would then stat() all the files in %INC
periodically. If one had changed, it'd attempt to compile it (if
WatcherCompileCheck was true) catching/absorbing any errors to prevent ugly
output, and then restart the apache server by sending it a signal if the
file compiled okay.

Doing a full restart avoids all the odd module re-load issues (and there are
many). The polling interval may seem too long, but this would all happen as
you were working on the code and before you reached back to a browser window
to reload a page. By the time you did, the hope was that the server would
already be back up again.

One obvious improvement would be to use kqueue/inotify/FSEvents to avoid
polling entirely, making it much more likely that the server would be back
in time for your next request.

-John

Re: a better way to recognize module changes

am 14.09.2009 18:43:34 von Perrin Harkins

On Fri, Sep 11, 2009 at 6:18 PM, Jonathan Swartz wrote:
> But if you change a module, wouldn't your first subsequent request hit the
> 'old' code? That's the benefit of an independent watcher, it'll operate in
> the time between when you've changed your module and when you hit the server
> again.

That's true. You could have it check for changes at the beginning of
the request, and if it sees any it could send a redirect to itself and
kill the current process. Not perfect though. I think the way you
suggested sounds fine.

- Perrin

Re: a better way to recognize module changes

am 14.09.2009 18:45:35 von Perrin Harkins

That's the simplest way to do it. If you want to get fancy you can
use a cleanup handler to diff %INC after requests and log anything
new.

- Perrin

On Fri, Sep 11, 2009 at 6:22 PM, Jonathan Swartz wrote:
> Incidentally Perrin - how do you come up with the list of vendor (i.e. no=
t
> your project's) modules to load in the parent? Do you just load a page, l=
ook
> at %INC, and then subtract out your personal modules? Do you have to do t=
his
> every so often to catch new vendor modules that have snuck in as
> dependencies?
>
> On Sep 11, 2009, at 2:52 PM, Perrin Harkins wrote:
>
>> On Fri, Sep 11, 2009 at 5:26 PM, Jonathan Swartz wrot=
e:
>>>
>>> This is the nicest solution I've seen so far. The only problem I can se=
e
>>> is
>>> its performance - each potentially-changing module has to be loaded on
>>> each
>>> request. **
>>
>> How long does it take for you? =A0I've run a lot of large mod_perl apps
>> this way and never seen it take more than 3 seconds to compile and
>> generate a page. =A0Maybe this is only an issue with Moose? =A0Or maybe
>> there's some expensive initialization that could be skipped in
>> development?
>>
>> Anyway, another approach would be to set MaxClients to 1 and install
>> cleanup handler that kills the current process if it sees that any of
>> the watched modules have been changed. =A0Then you don't need a separate
>> process.
>>
>> - Perrin
>
>

Re: a better way to recognize module changes

am 27.05.2010 17:11:15 von Michael Schout

On 09/11/2009 04:26 PM, Jonathan Swartz wrote:
> I'm thinking about an improved solution to recognizing module changes in
> a running server, without restarting the server.

This thread is quite old, but it inspired me to implement a similar
strategy for dealing with module changes under mod_perl.

In my case, I was only really interested in restarting the server when
modules under a certain namespace changed (all of my app's modules are
under a single namespace, "My" for example).

My solution involved forking off a watcher process when the server
starts up. This watcher processes uses File::ChangeNotify to watch for
changes in the given modules. A nice benefit of using ::ChangeNotify,
is if you are on Linux, and have the Linux::Inotify2 modules installed,
then this happens with no cpu overhead, and changes are seen almost
instantaneous. Once a change happens, my watcher processes detaches
from apache, and reloads it (retrying some configured number of times in
case there is a syntax error on the first change).

To do this, I created a module My::Apache2::Reload. I register the
handler in httpd.conf as:

PerlPostConfigHandler My::Apache2::Reload

When apache starts up, it immediately restarts itself, so my handler has
to arrange to only start the watcher subprocess one time. I do this on
the second restart like this:

> sub handler : method {
> return Apache2::Const::OK unless Apache2::ServerUtil::restart_count() == 2;
>
> start_watcher();
>
> return Apache2::Const::OK;
> }

start_watcher is implemented as follows:

> sub start_watcher {
> unless (fork) { # child
> require File::ChangeNotify;
>
> my $module_dir = '/path/to/my/modules';
> my $config_dir = '/path/to/my/configs';
>
> my $watcher = File::ChangeNotify->instantiate_watcher(
> directories => [$module_dir, $config_dir],
> filter => qr/\.(?:pm|conf|yml)$/);
>
> while (my @events = $watcher->wait_for_events) {
> my @event_types = map { $_->type } @events;
> if (any(@event_types) eq 'modify') {
> restart_apache();
> }
> }
> }
> }

And restart_apache() is called when something that is watched changes:

> sub restart_apache {
> disconnect_from_apache();
>
> require IPC::System::Simple;
>
> for my $attempt (1 .. $MaxRestartTries) {
> if ($attempt > 1) {
> sleep $RestartDelay;
> }
>
> eval {
> IPC::System::Simple::system('apache restart command');
> CORE::exit(0);
> };
> }
>
> # give up.
> CORE::exit(0);
> }

The disconnect_from_apache() is necessary because the watcher gets
killed off if you do not close all open filehandles in the child when
the restart is attempted. Also we need to detach from the apache
process group. This is done as follows:

> sub disconnect_from_apache {
> POSIX::setsid();
>
> # close all open fds.
> my $max_fds = POSIX::sysconf(&POSIX::_SC_OPEN_MAX) // 64;
>
> for my $fd (0 .. $max_fds) {
> POSIX::close($fd);
> }
> }


And thats it. This has worked wonderfully for me. Apache notices
changes in real time, and restarts happen quickly when developing.

If there is interest in a module like this, let me know and I will
package it up and put it on CPAN (obviously I wouldn't use the name
Apache2::Reload as that is taken already :)).

Regards,
Michael Schout

Re: a better way to recognize module changes

am 27.05.2010 22:04:33 von Perrin Harkins

On Thu, May 27, 2010 at 11:11 AM, Michael Schout wrote:
> My solution involved forking off a watcher process when the server
> starts up.

Wouldn't it be simpler to start a separate daemon for this? You could
launch it from apachectl if you don't want to run another command.

- Perrin

Re: a better way to recognize module changes

am 27.05.2010 23:48:53 von Michael Schout

On 05/27/2010 03:04 PM, Perrin Harkins wrote:
> On Thu, May 27, 2010 at 11:11 AM, Michael Schout wrote:
>> My solution involved forking off a watcher process when the server
>> starts up.
>
> Wouldn't it be simpler to start a separate daemon for this?

The project this is for has apache's sandboxed for each developer.
Every developer runs their own apache on a port number based on their
UID. By having apache fork the watcher daemon, I don't have to worry
about which apache the watcher is in charge of. Also, apache will kill
the watcher when apache is killed, so I do not need to manage the
watcher daemon at all. Apache takes care of starting and stopping it
for me.

Regards,
Michael Schout

Re: a better way to recognize module changes

am 27.05.2010 23:54:00 von Fred Moyer

Curiously, I have been using Apache::Reload a lot lately and it has
been working really well most of the time.

I'm wondering if maybe another way to deal with troublesome module
reloads is to subclass Apache::Reload and override the reload process
for those specific namespaces.

On Thu, May 27, 2010 at 8:11 AM, Michael Schout wrote:
> On 09/11/2009 04:26 PM, Jonathan Swartz wrote:
>> I'm thinking about an improved solution to recognizing module changes in
>> a running server, without restarting the server.
>
> This thread is quite old, but it inspired me to implement a similar
> strategy for dealing with module changes under mod_perl.
>
> In my case, I was only really interested in restarting the server when
> modules under a certain namespace changed (all of my app's modules are
> under a single namespace, "My" for example).
>
> My solution involved forking off a watcher process when the server
> starts up. =A0This watcher processes uses File::ChangeNotify to watch for
> changes in the given modules. =A0A nice benefit of using ::ChangeNotify,
> is if you are on Linux, and have the Linux::Inotify2 modules installed,
> then this happens with no cpu overhead, and changes are seen almost
> instantaneous. =A0Once a change happens, my watcher processes detaches
> from apache, and reloads it (retrying some configured number of times in
> case there is a syntax error on the first change).
>
> To do this, I created a module My::Apache2::Reload. =A0I register the
> handler in httpd.conf as:
>
> PerlPostConfigHandler My::Apache2::Reload
>
> When apache starts up, it immediately restarts itself, so my handler has
> to arrange to only start the watcher subprocess one time. =A0I do this on
> the second restart like this:
>
>> sub handler : method {
>> =A0 =A0 return Apache2::Const::OK unless Apache2::ServerUtil::restart_co=
unt() == 2;
>>
>> =A0 =A0 start_watcher();
>>
>> =A0 =A0 return Apache2::Const::OK;
>> }
>
> start_watcher is implemented as follows:
>
>> sub start_watcher {
>> =A0 =A0 unless (fork) { # child
>> =A0 =A0 =A0 =A0 require File::ChangeNotify;
>>
>> =A0 =A0 =A0 =A0 my $module_dir =3D '/path/to/my/modules';
>> =A0 =A0 =A0 =A0 my $config_dir =3D '/path/to/my/configs';
>>
>> =A0 =A0 =A0 =A0 my $watcher =3D File::ChangeNotify->instantiate_watcher(
>> =A0 =A0 =A0 =A0 =A0 =A0 directories =3D> [$module_dir, $config_dir],
>> =A0 =A0 =A0 =A0 =A0 =A0 filter =A0 =A0  => qr/\.(?:pm|conf|yml)$/);
>>
>> =A0 =A0 =A0 =A0 while (my @events =3D $watcher->wait_for_events) {
>> =A0 =A0 =A0 =A0 =A0 =A0 my @event_types =3D map { $_->type } @events;
>> =A0 =A0 =A0 =A0 =A0 =A0 if (any(@event_types) eq 'modify') {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 restart_apache();
>> =A0 =A0 =A0 =A0 =A0 =A0 }
>> =A0 =A0 =A0 =A0 }
>> =A0 =A0 }
>> }
>
> And restart_apache() is called when something that is watched changes:
>
>> sub restart_apache {
>> =A0 =A0 disconnect_from_apache();
>>
>> =A0 =A0 require IPC::System::Simple;
>>
>> =A0 =A0 for my $attempt (1 .. $MaxRestartTries) {
>> =A0 =A0 =A0 =A0 if ($attempt > 1) {
>> =A0 =A0 =A0 =A0 =A0 =A0 sleep $RestartDelay;
>> =A0 =A0 =A0 =A0 }
>>
>> =A0 =A0 =A0 =A0 eval {
>> =A0 =A0 =A0 =A0 =A0 =A0 IPC::System::Simple::system('apache restart comm=
and');
>> =A0 =A0 =A0 =A0 =A0 =A0 CORE::exit(0);
>> =A0 =A0 =A0 =A0 };
>> =A0 =A0 }
>>
>> =A0 =A0 # give up.
>> =A0 =A0 CORE::exit(0);
>> }
>
> The disconnect_from_apache() is necessary because the watcher gets
> killed off if you do not close all open filehandles in the child when
> the restart is attempted. =A0Also we need to detach from the apache
> process group. =A0This is done as follows:
>
>> sub disconnect_from_apache {
>> =A0 =A0POSIX::setsid();
>>
>> =A0 =A0# close all open fds.
>> =A0 =A0my $max_fds =3D POSIX::sysconf(&POSIX::_SC_OPEN_MAX) // 64;
>>
>> =A0 =A0for my $fd (0 .. $max_fds) {
>> =A0 =A0 =A0 =A0POSIX::close($fd);
>> =A0 =A0}
>> }
>
>
> And thats it. =A0This has worked wonderfully for me. =A0Apache notices
> changes in real time, and restarts happen quickly when developing.
>
> If there is interest in a module like this, let me know and I will
> package it up and put it on CPAN (obviously I wouldn't use the name
> Apache2::Reload as that is taken already :)).
>
> Regards,
> Michael Schout
>

Re: a better way to recognize module changes

am 28.05.2010 00:07:48 von Jonathan Swartz

On May 27, 2010, at 1:04 PM, Perrin Harkins wrote:

> On Thu, May 27, 2010 at 11:11 AM, Michael Schout
> wrote:
>> My solution involved forking off a watcher process when the server
>> starts up.
>
> Wouldn't it be simpler to start a separate daemon for this? You could
> launch it from apachectl if you don't want to run another command.
>

Also take a look at Server::Control::Apache (apachectlp), it is easy
to extend its behavior to, e.g., launch a separate daemon.