]> git.ktnx.net Git - mpd-feeder.git/commitdiff
re-exec on SIGHUP, picking up configuration file changes
authorDamyan Ivanov <dmn@debian.org>
Thu, 11 Nov 2021 14:43:57 +0000 (14:43 +0000)
committerDamyan Ivanov <dmn@debian.org>
Thu, 11 Nov 2021 14:43:57 +0000 (14:43 +0000)
my first approach was to just re-read the config, but could not make
the idle/playlist loop  behave. it gets stuck with responses getting
lost and eventually is disconnected my MPD due to timeout

re-exec works, but there is a (very small) chance of missing a database
update between disconnection and re-connection to MPD.

bin/mpd-feeder

index a5454424ae16200d4cd6331cae816fbf5f25d92e..b671b369d1fd473796ef4759c355ee443ee07d52 100755 (executable)
@@ -110,6 +110,7 @@ class Options {
 }
 
 class Feeder {
+    has $cfg_file :reader;
     has $opt :reader;
     has $db;
     has $db_generation;
@@ -121,27 +122,31 @@ use constant DEFAULT_CONFIG_FILE => '/etc/mpd-feeder/mpd-feeder.conf';
 use DBD::Pg;
 use DBI;
 use Log::Any qw($log);
+use IO::Async::Signal;
 use Net::Async::MPD;
 
     ADJUST {
-        $opt = Options->new;
+        Getopt::Long::Configure('pass_through');
+        Getopt::Long::GetOptions('cfg|config=s' => \$cfg_file);
+        Getopt::Long::Configure('no_pass_through');
 
-        {
-            my $cfg_file;
-            Getopt::Long::Configure('pass_through');
-            Getopt::Long::GetOptions('cfg|config=s' => \$cfg_file);
-            Getopt::Long::Configure('no_pass_through');
+        $cfg_file //= DEFAULT_CONFIG_FILE if -e DEFAULT_CONFIG_FILE;
 
-            $cfg_file //= DEFAULT_CONFIG_FILE if -e DEFAULT_CONFIG_FILE;
+        $self->configure;
 
-            $opt->parse_config_file($cfg_file) if $cfg_file;
-        }
+        $db_needs_update = 0 if $opt->skip_db_update;
+    }
 
-        $opt->parse_command_line;
+    method configure {
+        my $new_opt = Options->new;
 
-        $db_needs_update = 0 if $opt->skip_db_update;
+        $new_opt->parse_config_file($cfg_file) if $cfg_file;
+
+        $new_opt->parse_command_line;
+
+        Log::Any::Adapter->set( Stderr => log_level => $new_opt->log_level );
 
-        Log::Any::Adapter->set( Stderr => log_level => $opt->log_level );
+        $opt = $new_opt;
     }
 
     method connect_mpd {
@@ -152,6 +157,16 @@ use Net::Async::MPD;
         $conn{port} = $opt->mpd_port if $opt->mpd_port;
 
         $mpd = Net::Async::MPD->new(%conn);
+
+        $mpd->loop->add(
+            IO::Async::Signal->new(
+                name       => 'HUP',
+                on_receipt => sub {
+                    $log->debug("SIGHUP received. Stopping loop");
+                    $mpd->loop->stop('reload');
+                },
+            )
+        );
     }
 
     method connect_db {
@@ -440,6 +455,25 @@ SQL
 
         $self->prepare_to_wait_idle;
     }
+
+    method stop {
+        undef $mpd;
+
+        if ($db) {
+            if ($db->{ActiveKids}) {
+                $log->warn("$db->{ActiveKids} active DB statements");
+                for my $st ( @{ $db->{ChildHandles} } ) {
+                    next unless $st->{Active};
+                    while(my($k,$v) = each %$st) {
+                        $log->debug("$k = ".($v//'<NULL>'));
+                    }
+                }
+            }
+
+            $db->disconnect;
+            undef $db;
+        }
+    }
 }
 
 my $feeder = Feeder->new();
@@ -503,6 +537,18 @@ if (@ARGV) {
     }
 }
 
-$feeder->queue_songs( undef, sub { $feeder->run } );
+for ( ;; ) {
+    $feeder->queue_songs( undef, sub { $feeder->run } );
 
-$feeder->mpd->loop->run;
+    $log->debug("Entering event loop. PID=$$");
+
+    my $result = $feeder->mpd->loop->run;
+    $log->trace( "Got loop result of " . ( $result // 'undef' ) );
+
+    if ('reload' eq $result) {
+        $log->notice("disconnecting");
+        $feeder->stop;
+
+        exec( "$0", '--config', $feeder->cfg_file, '--skip-db-update' );
+    }
+}