#!/usr/bin/perl

use strict;
use warnings;

use Instance;
our $megaName = "example ";
our %PIDs;
our @PKs = ('test1','test2');

$0 = $megaName."(manager)";
open (PID,">./pids/manager.pid");
print PID $$;
close (PID);

my $processToRun  = scalar @PKs;

RUNDAEMONS: while (1) 
{
    my $onAir = 0;
    $onAir = scalar keys %PIDs; 

    if ($onAir < $processToRun)
    {
        # Если детеныш умер или не родился
        my $pk = getNextChildName();

        my $connectParameters = getConnectionParams($pk);
        if (not defined ($connectParameters))
        {
            print "Connection: ".$pk." doesn`t exists!\n";
            my @newPks;
            for my $index (@PKs)
            {
                if (not $pk eq $index)
                {
                    @newPks[scalar @newPks] = $index;
                }
            }
            @PKs = @newPks;
            $processToRun  = scalar @PKs;
            next RUNDAEMONS;
        }

        if (my $pid = fork()) 
        { # здесь остался родитель
            $PIDs{$pk} = $pid;
        } else {
            # а тут у нас детеныш
            my $instance = Instance->new(%$connectParameters);
            $0 = $megaName."(instance) [".$pk."]";
            open (PID,">./pids/".$pk.".pid");
            print PID $$ ;
            close (PID);
            
            $instance->run();
            die();
        }
    }
    if ($onAir < $processToRun)
    {
        # если не все еще родились
        next RUNDAEMONS;
    }

    my $dead = wait();
    for my $key ( keys %PIDs ) 
    {
        my $value = $PIDs{$key};
        if ($value == $dead)
        {
            delete $PIDs{$key};
            print "Instance: ".$key." is dead (".$dead.")!\n";
            next RUNDAEMONS;
        }
    }
    sleep 5;
}
print $megaName." completly die!";


# получить имя следуещего детеныша
sub getNextChildName
{
    for my $index (@PKs)
    {
        if (not defined ($PIDs{$index}) )
        {
            return $index;
        }
    }
}

# получить параметры для подключения    
sub getConnectionParams
{
    my $name = shift;
    {'a'=>1,'b'=>2,'name'=>$name};
}

#до конца пример кода из файла Instance.pm
package Instance;

use strict;
use warnings;

use Data::Dumper;

sub new 
{
    my $type = shift;
    my %params = @_;
    my $self = {};

    $self = {%params};
    bless $self, $type;
}

sub run
{
    my $self = shift;

    print "I am here: ".$self->{name}. " !\n";
    print Dumper $self;

    while(1)
    {
        sleep 5;
    }
}

1;