#!/usr/bin/env perl use strict; use warnings; use FindBin; FindBin::again(); use Path::Class 'dir'; # get a segfault if we load this later use if $^O eq 'linux', 'Sys::Proctitle'; BEGIN { # stuff useful locations into @INC unshift @INC, dir($FindBin::RealBin)->parent->subdir('lib')->stringify, dir($FindBin::RealBin, 'lib')->stringify; unshift @INC, split m/:/, ($ENV{NETDISCO_INC} || ''); } use App::Netdisco; use Dancer qw/:moose :script/; warning sprintf "App::Netdisco %s backend", ($App::Netdisco::VERSION || 'HEAD'); use App::Netdisco::Util::Daemon; use NetAddr::IP::Lite ':lower'; # to quench AF_INET6 symbol errors use Role::Tiny::With; use MCE::Signal '-setpgrp'; use MCE::Flow Sereal => 1; use MCE::Queue; # set temporary MCE files' location in home directory my $home = ($ENV{NETDISCO_HOME} || $ENV{HOME}); my $tmp_dir = ($ENV{NETDISCO_TEMP} || dir($home, 'tmp')); mkdir $tmp_dir if ! -d $tmp_dir; setpgrp(0,0); # only portable variety of setpgrp prctl 'netdisco-daemon: master'; # shared local job queue my $Q = MCE::Queue->new; mce_flow { task_name => [qw/ scheduler manager poller /], max_workers => [ 1, 1, 'AUTO * 2' ], # FIXME allow setting override tmp_dir => $tmp_dir, on_post_exit => sub { MCE->restart_worker() }, }, _mk_wkr('Scheduler'), _mk_wkr('Manager'), _mk_wkr('Poller'); sub _mk_wkr { my $role = shift; return sub { my $self = shift; my $wid = $self->wid; $self->{Q} = $Q; # FIXME make it a method prctl sprintf 'netdisco-daemon: worker #%s %s: init', $wid, lc($role); info "applying role $role to worker $wid"; # post-fork, become manager, scheduler, poller, etc Role::Tiny->apply_roles_to_object( $self => "App::Netdisco::Daemon::Worker::$role"); $self->worker_begin if $self->can('worker_begin'); $self->worker_body; }; } #use List::Util 'sum'; #sub num_workers { # return sum( 0, map { setting('workers')->{$_} } # values %{setting('job_type_keys')} ); #} #sub restart_this_worker { # my ($self, $e) = @_; # reset_jobs($e->{wid}); # # debug "restarting worker ". MCE->wid(); # MCE->restart_worker(); # $self->restart_worker($e->{wid}); #} #sub build_tasks_list { # # NB MCE does not like max_workers => 0 # my $tasks = []; # # push @$tasks, { # max_workers => 1, # user_begin => worker_factory('Manager'), # } if num_workers() > 0; # # push @$tasks, { # max_workers => 1, # user_begin => worker_factory('Scheduler'), # } if setting('schedule'); # # my @logmsg = (); # foreach my $key (keys %{setting('job_type_keys')}) { # my $val = setting('job_type_keys')->{$key}; # # setting('workers')->{$val} = 2 # if !defined setting('workers')->{$val}; # # push @logmsg, setting('workers')->{$val} ." $key"; # push @$tasks, { # max_workers => setting('workers')->{$val}, # user_begin => worker_factory($key), # } if setting('workers')->{$val}; # } # # info sprintf "MCE will load: %s Manager, %s Scheduler, %s", # (num_workers() ? 1 : 0), # (setting('schedule') ? 1 : 0), # (join ', ', @logmsg); # # return $tasks; #} #sub worker_factory { # my $role = shift; # return sub { # my $self = shift; # my $wid = $self->wid; # prctl sprintf 'netdisco-daemon: worker #%s %s: init', $wid, lc($role); # info "applying role $role to worker $wid"; # # # $self->sendto('stderr', ">>> worker $wid starting with role $role\n"); # Role::Tiny->apply_roles_to_object($self, "App::Netdisco::Daemon::Worker::$role"); # # $self->worker_begin if $self->can('worker_begin'); # }; #} #my $mce = MCE->new( # spawn_delay => 0.15, # job_delay => 1.15, # tmp_dir => $tmp_dir, # user_func => sub { $_[0]->worker_body }, # on_post_exit => \&restart_this_worker, # user_tasks => build_tasks_list(), #)->run(); =head1 NAME netdisco-daemon-fg - Job Control for Netdisco =head1 SEE ALSO =over 4 =item * L =back =cut