From 9e4d82449580078244d6a88ac0a94eea0c5d999e Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 11 Nov 2021 14:43:57 +0000 Subject: [PATCH] re-exec on SIGHUP, picking up configuration file changes 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 | 74 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/bin/mpd-feeder b/bin/mpd-feeder index a545442..b671b36 100755 --- a/bin/mpd-feeder +++ b/bin/mpd-feeder @@ -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//'')); + } + } + } + + $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' ); + } +} -- 2.39.2