<commit_before>
=head1 NAME

VRPipe::Persistent::Living - a class to extend from if you can be alive or dead

=head1 SYNOPSIS

*** more documentation to come

=head1 DESCRIPTION

*** more documentation to come

=head1 AUTHOR

<NAME> <<EMAIL>>.

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2012 Genome Research Limited.

This file is part of VRPipe.

VRPipe is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see L<http://www.gnu.org/licenses/>.

=cut

use VRPipe::Base;

class VRPipe::Persistent::Living extends VRPipe::Persistent {
    use DateTime;
    use EV;
    use AnyEvent;
    
    has 'heartbeat' => (
        is          => 'rw',
        isa         => Datetime,
        coerce      => 1,
        traits      => ['VRPipe::Persistent::Attributes'],
        is_nullable => 1
    );
    
    has 'heartbeat_interval' => (
        is      => 'rw',
        isa     => PositiveInt,
        lazy    => 1,
        builder => '_build_default_heartbeat_interval'
    );
    
    has 'heart' => (
        is      => 'rw',
        isa     => 'Object',
        lazy    => 1,
        builder => '_build_heart',
        handles => { start_beating => 'start', stop_beating => 'stop' }
    );
    
    has 'survival_time' => (
        is      => 'rw',
        isa     => PositiveInt,
        lazy    => 1,
        builder => '_build_default_survival_time'
    );
    
    has 'reaction_to_being_murdered' => (
        is      => 'rw',
        isa     => 'Object',
        lazy    => 1,
        builder => '_build_default_murder_reaction',
        handles => { react_to_being_murdered => 'start', ignore_being_murdered => 'stop' }
    );
    
    method _build_default_heartbeat_interval {
        if (VRPipe::Persistent::SchemaBase->database_deployment eq 'testing') {
            return 3;
        }
        else {
            return 60;
        }
    }
    
    method _build_default_survival_time {
        my $interval = $self->heartbeat_interval;
        
        # try and allow for mysql server time being different to our host time,
        # and other related timing vagaries
        my $multiplier;
        if ($interval < 60) {
            $multiplier = 10;
        }
        elsif ($interval < 300) {
            $multiplier = 3;
        }
        else {
            $multiplier = 1;
        }
        
        return $interval * $multiplier;
    }
    
    method _build_heart {
        return EV::periodic_ns 0, $self->heartbeat_interval, 0, sub {
            $self->beat_heart if $self->_still_exists;
        };
    }
    
    method _build_default_murder_reaction {
        my $watcher;
        $watcher = EV::periodic_ns 0, $self->heartbeat_interval, 0, sub {
            return if $self->_still_exists;
            $self->stop_beating;
            $watcher->stop;
            $self->delete if $self->_still_exists;
            EV::unloop;
            die "We were murdered by another process\n";
        };
        return $watcher;
    }
    
    method time_since_heartbeat {
        my $heartbeat = $self->heartbeat || return 0;
        my $t = time();
        return $t - $heartbeat->epoch;
    }
    
    method alive {
        my $alive = $self->_still_exists;
        if ($alive) {
            $alive = $self->time_since_heartbeat <= $self->survival_time ? 1 : 0;
        }
        unless ($alive) {
            $self->stop_beating;
            $self->delete;
        }
        return $alive;
    }
    
    method _still_exists {
        my $still_exists = $self->search({ id => $self->id });
        return $still_exists;
    }
    
    method beat_heart {
        $self->heartbeat(DateTime->now());
        $self->update;
        $self->disconnect;
    }
    
    method commit_suicide {
        $self->stop_beating;
        $self->delete if $self->_still_exists;
        exit 0;
    }
}
<commit_msg>commit_suicide() now dies instead of exiting, so it can be caught<commit_after>
=head1 NAME

VRPipe::Persistent::Living - a class to extend from if you can be alive or dead

=head1 SYNOPSIS

*** more documentation to come

=head1 DESCRIPTION

*** more documentation to come

=head1 AUTHOR

<NAME> <<EMAIL>>.

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2012 Genome Research Limited.

This file is part of VRPipe.

VRPipe is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see L<http://www.gnu.org/licenses/>.

=cut

use VRPipe::Base;

class VRPipe::Persistent::Living extends VRPipe::Persistent {
    use DateTime;
    use EV;
    use AnyEvent;
    
    has 'heartbeat' => (
        is          => 'rw',
        isa         => Datetime,
        coerce      => 1,
        traits      => ['VRPipe::Persistent::Attributes'],
        is_nullable => 1
    );
    
    has 'heartbeat_interval' => (
        is      => 'rw',
        isa     => PositiveInt,
        lazy    => 1,
        builder => '_build_default_heartbeat_interval'
    );
    
    has 'heart' => (
        is      => 'rw',
        isa     => 'Object',
        lazy    => 1,
        builder => '_build_heart',
        handles => { start_beating => 'start', stop_beating => 'stop' }
    );
    
    has 'survival_time' => (
        is      => 'rw',
        isa     => PositiveInt,
        lazy    => 1,
        builder => '_build_default_survival_time'
    );
    
    has 'reaction_to_being_murdered' => (
        is      => 'rw',
        isa     => 'Object',
        lazy    => 1,
        builder => '_build_default_murder_reaction',
        handles => { react_to_being_murdered => 'start', ignore_being_murdered => 'stop' }
    );
    
    method _build_default_heartbeat_interval {
        if (VRPipe::Persistent::SchemaBase->database_deployment eq 'testing') {
            return 3;
        }
        else {
            return 60;
        }
    }
    
    method _build_default_survival_time {
        my $interval = $self->heartbeat_interval;
        
        # try and allow for mysql server time being different to our host time,
        # and other related timing vagaries
        my $multiplier;
        if ($interval < 60) {
            $multiplier = 10;
        }
        elsif ($interval < 300) {
            $multiplier = 3;
        }
        else {
            $multiplier = 1;
        }
        
        return $interval * $multiplier;
    }
    
    method _build_heart {
        return EV::periodic_ns 0, $self->heartbeat_interval, 0, sub {
            $self->beat_heart if $self->_still_exists;
        };
    }
    
    method _build_default_murder_reaction {
        my $watcher;
        $watcher = EV::periodic_ns 0, $self->heartbeat_interval, 0, sub {
            return if $self->_still_exists;
            $self->stop_beating;
            $watcher->stop;
            $self->delete if $self->_still_exists;
            EV::unloop;
            die "We were murdered by another process\n";
        };
        return $watcher;
    }
    
    method time_since_heartbeat {
        my $heartbeat = $self->heartbeat || return 0;
        my $t = time();
        return $t - $heartbeat->epoch;
    }
    
    method alive {
        my $alive = $self->_still_exists;
        if ($alive) {
            $alive = $self->time_since_heartbeat <= $self->survival_time ? 1 : 0;
        }
        unless ($alive) {
            $self->stop_beating;
            $self->delete;
        }
        return $alive;
    }
    
    method _still_exists {
        my $still_exists = $self->search({ id => $self->id });
        return $still_exists;
    }
    
    method beat_heart {
        $self->heartbeat(DateTime->now());
        $self->update;
        $self->disconnect;
    }
    
    method commit_suicide {
        $self->stop_beating;
        $self->delete if $self->_still_exists;
        die "committing suicide\n";
    }
}

{'fraction_non_alphanumeric': 0.10533547057476529, 'fraction_numerical': 0.008129150446530798, 'mean_word_length': 1.918476445038423, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 131, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1991065', 'n_tokens_mistral': 2699, 'n_tokens_neox': 2578, 'n_words': 741}