package POEDaemon::System; use strict; use warnings FATAL => 'all'; no warnings 'redefine'; use Data::Dumper; use POE; use POEDaemon; sub states { return $_[0], [qw( _default _start _stop _child signal_handler sig_chld sig_die shutdown shutdown_stage2 tick console_destroy )]; } sub _default { my ($session, $event, $args) = @_[SESSION, ARG0, ARG1]; log_enabled && logline "session '%s' caught unhandled event:\n%s\nwith args:\n%s", $session->ID, Dumper($event), Dumper($args); } sub _start { my ($kernel, $session, $heap, $args) = @_[KERNEL, SESSION, HEAP, ARG0]; $heap->{poe_init_time} = time_hires; unless (argv_quiet) { log_enabled && logline 'create console POE::Wheel::ReadWrite ( STDIN / STDOUT )'; $heap->{console} = POE::Wheel::ReadWrite->new ( InputHandle => \*STDIN, OutputHandle => \*STDOUT, ); } syslogline '#3, start', { high_priority => 1 } if cfg->{syslog_high_priority_debug}; log_enabled && logline "start, script = '%s'", $heap->{script} || 'n/a'; #foreach my $signal (qw(HUP INT TERM DIE IDLE)) foreach my $signal (qw(HUP INT TERM INFO USR1 USR2)) { $kernel->sig($signal => 'signal_handler'); } #$kernel->sig(CHLD => 'sig_chld'); $kernel->sig(DIE => 'sig_die'); log_enabled && logline "kernel->alias_set('%s')", MAIN_POE_SESSION_NAME; $kernel->alias_set(MAIN_POE_SESSION_NAME); $kernel->yield('tick'); foreach (sort keys %{$session->[POE::Session::SE_STATES]}) { next if /^POE::/i; log_enabled && logline "found session state '%s'", $_; next unless /^.+_start$/; log_enabled && logline "yield '%s'", $_; $kernel->yield($_); } prod_log_enabled && prod_logline 'start'; if (exists $heap->{statelist}->{eventsystem_input} && $heap->{statelist}->{eventsystem_input}) { $kernel->yield(eventsystem_input => { type => 'init', time => time_hires, }); } } sub _stop { my ($kernel, $heap, $args) = @_[KERNEL, HEAP, ARG0]; log_enabled && logline "stop, script = '%s'", $heap->{script} || 'n/a'; log_enabled && logline "uptime = %s", duration_exact time - $^T; log_enabled && logline "shutdown_reason = '%s'", $heap->{shutdown_reason} || 'n/a'; my $exitmsg = sprintf "shutdown_reason = '%s'", $heap->{shutdown_reason} || 'n/a'; exitmsg_set $exitmsg; } sub _child { log_enabled && logline 'event fired'; } sub signal_handler { my ($kernel, $session, $heap, $signal) = @_[KERNEL, SESSION, HEAP, ARG0]; if ($signal eq 'INT' && !argv_quiet) { print "\n"; } log_enabled && logline "signal_handler: SIG%s", $signal; if ($signal =~ /^(INT|TERM)$/) { $kernel->yield(shutdown => sprintf "SIG%s", $signal); } elsif ($signal eq 'HUP') { if ($heap->{statelist}->{reload}) { $kernel->call($session => 'reload'); } } elsif ($signal eq 'INFO') { #log_enabled && logline "\nHEAP:\n%s", Dumper $heap; if ($heap->{statelist}->{stats}) { $kernel->yield('stats'); } } elsif ($signal eq 'USR1') { if ($heap->{statelist}->{reload}) { $kernel->call($session => reload => { subcmd => 'force,clear', }); } } elsif ($signal eq 'USR2') { log_enabled && logline "%s / uptime = %s", $heap->{script}, duration_exact time - $^T; } $kernel->sig_handled; } sub sig_chld { my ($kernel, $heap) = @_[KERNEL, HEAP]; log_enabled && logline 'sig_chld'; $kernel->sig_handled; } sub sig_die { my ($kernel, $session, $signal, $exception) = @_[KERNEL, SESSION, ARG0, ARG1]; my $event = $exception->{event}; my $error_str = $exception->{error_str}; $error_str =~ s/\s+$//; #my $exception_log; # # #foreach my $key (keys %{$exception}) #{ # next if $key =~ /^(?:source|dest)_session$/; # # # $exception_log->{$key} = $exception->{$key}; #} #log_enabled && logline "from file=%s line=%s state=%s -> error in %s: %s\n%s", #log_enabled && logline "from file=%s line=%s state=%s -> error in %s: %s", $exception->{file}, $exception->{line}, $exception->{from_state} || 'n/a', $event, $error_str; #Dumper [ $signal, $exception_log ]; #Dumper [ $exception ]; if ($error_str =~ /Framing\s+buffer\s+exceeds\s+the\s+limit/i && $event =~ /POE::Wheel::ReadWrite\((\d+)\)/i) { my $error_wheel_id = $1; #log_enabled && logline "buffer full, wheel #%s", $error_wheel_id; $kernel->call($session => tcpserver_client_filter_buffer_full_error => { error_wheel_id => $error_wheel_id, }); } $kernel->sig_handled; if ($exception->{source_session} ne $session) { $poe_kernel->signal($exception->{source_session} => DIE => $signal => $exception); } } sub shutdown { my ($kernel, $heap, $reason) = @_[KERNEL, HEAP, ARG0]; log_enabled && logline 'shutdown'; $heap->{shutdown} = 1; $heap->{shutdown_reason} = sprintf "%s%s%s%s", $reason, (defined $heap->{systemupgrade_active} ? sprintf " upgrade_active=%s", $heap->{systemupgrade_active} : ''), (defined $heap->{systemupgrade_exitcode} ? sprintf " upgrade_exitcode=%s", $heap->{systemupgrade_exitcode} : ''), (defined $heap->{sysreboot_active} ? sprintf " reboot_active=%s", $heap->{sysreboot_active} : ''); prod_log_enabled && prod_logline "shutdown: %s", dumper_oneline $heap->{shutdown_reason}; if (exists $heap->{statelist}->{eventsystem_input} && $heap->{statelist}->{eventsystem_input}) { $kernel->yield(eventsystem_input => { type => 'shutdown', reason => $heap->{shutdown_reason}, time => time_hires, }); } } sub shutdown_stage2 { my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP]; if ($heap->{tasks}->{executed}->{shutdown_stage2}) { return; } $heap->{tasks}->{executed}->{shutdown_stage2} = 1; log_enabled && logline 'shutdown_stage2'; $kernel->alarm_remove_all; foreach my $alias ($kernel->alias_list) { log_enabled && logline "kernel->alias_remove('%s')", $alias; $kernel->alias_remove($alias); } foreach (sort keys %{$session->[POE::Session::SE_STATES]}) { next unless /^.+_stop$/; log_enabled && logline "yield '%s'", $_; $kernel->yield($_); } unless (argv_quiet) { $heap->{console}->event(FlushedEvent => 'console_destroy') if $heap->{console}; log_enabled && logline 'destroy console POE::Wheel::ReadWrite ( STDIN / STDOUT )'; } } sub tick { my ($kernel, $heap) = @_[KERNEL, HEAP]; $heap->{ticks}++; foreach my $item (keys %{$heap->{periodic}}) { my $seconds = $heap->{periodic}->{$item}; if ($item && $seconds && $seconds =~ /^\d+$/ && ($heap->{ticks} % $seconds) == 0) { #log_enabled && logline "periodic: run '%s' every %ss", # $item, # $seconds; $kernel->yield($item); } } if (($heap->{ticks} % 3) == 0 && exists $heap->{statelist}->{watchdog}) { $kernel->yield(watchdog => sprintf("alivetime=%s", time)); } if ($heap->{shutdown}) { $kernel->yield('shutdown_stage2'); return; } $kernel->delay(tick => 1); } sub console_destroy { my $heap = $_[HEAP]; delete $heap->{console} if $heap->{console}; } 1;