1

I have a lot of small Perl daemons with a common configuration.

Currently, I use this to load the settings:

In myconfig.pm:

package MyConfig;
use base 'Exporter';

BEGIN {
    our @EXPORT = qw( $DB_DSN $DB_USER $DB_PWD );
}

our @EXPORT;
use vars @EXPORT;

$DB_DSN = "DBI:mysql:...";
$DB_USER = 'asdad';
...

And in daemon.pl:

use MyConfig;

This works just fine. But now I have the new requirement to reload the configuration when the USR1 signal is received. I know about

$SIG{"USR1"} = sub { ... }

but what next? use MyConfig again? Looks mad.

My scripts have to run on many different platforms and different perl versions from 5.8 to modern, so I'm trying to avoid CPAN modules.

Please point me to good solution about this task.

Korjavin Ivan
  • 439
  • 1
  • 5
  • 15

1 Answers1

2

When you use Module (ARGS), this is equivalent to

BEGIN {
  require Module;
  Module->import(ARGS);
}

The require locates and compiles the module. This happens only once for each module. The import runs the special import sub that usually loads subs and variables into the callers namespace (provided by the Exporter module). So

$SIG{USR1} = sub { no warnings 'redefine'; MyConfig->import };

may very well work for your problem.


Followup:

I wrote this little program to demonstrate that this works (using ALRM instead of USR1):

use 5.010;
package Foo;
sub import{ # The Exporter module writes something similar.
  no strict 'refs';
  *{caller()."::var"} = \do{ my$x = 1 }; # put $foo into callers namespace
}

package main;
Foo->import(); # use Foo; if the package were in another file
$SIG{ALRM} = sub{ Foo->import; alarm 10 };
alarm 10;
while(1){
  say $var++;
  sleep 1;
}

Output: Counting from 0 to roughly 10, again and again. Be aware that I change the variable inside the loop, so I can see that it changes and is reset correctly.

amon
  • 57,091
  • 2
  • 89
  • 149
  • Thanks you very for edit my questons. My english bad. But this solution doesnt work. Here is listing and log https://gist.github.com/korjavin/4737335 – Korjavin Ivan Feb 08 '13 at 07:46
  • @KorjavinIvan Your gist doesn't prove that it doesn't work - you never *change* your variable, which would allow to view the reset. Also, the `vars` pragma is deprecated: `our` provides all functionality. Try my added code to see that it works. – amon Feb 08 '13 at 08:11
  • I changed MyConfig.pm with my editor, and after that send kill -USR1. But reloaded.pl still print old value. I modify my gist, add alarm from you code, and add prove from MyConfig.pm file. gist.github.com/korjavin/4737335 – Korjavin Ivan Feb 08 '13 at 08:48
  • @KorjavinIvan Aah, now I get your problem. As I stated above, each module is only compiled once. You can force recompilation by re+`require`ing it after you delete it from the know modules. Change the handler to `delete $INC{"MyConfig.pm"}; require MyConfig; MyConfig->import`. Please note that the keys in `%INC` are filenames, not package names. – amon Feb 08 '13 at 08:57