File Coverage

blib/lib/Memorator.pm
Criterion Covered Total %
statement 27 94 28.7
branch 0 18 0.0
condition 0 8 0.0
subroutine 9 23 39.1
pod 3 3 100.0
total 39 146 26.7


line stmt bran cond sub pod time code
1             package Memorator;
2 1     1   1419 use strict;
  1         2  
  1         23  
3 1     1   4 use warnings;
  1         1  
  1         30  
4             { our $VERSION = '0.005001'; }
5              
6 1     1   332 use Memorator::Util ();
  1         1  
  1         20  
7 1     1   425 use Module::Runtime qw< use_module >;
  1         1379  
  1         5  
8              
9 1     1   480 use Mojo::Base -base;
  1         107381  
  1         8  
10 1     1   673 use Try::Tiny;
  1         840  
  1         46  
11              
12 1     1   6 use constant ATTEMPTS => 2; # default value
  1         2  
  1         40  
13 1     1   5 use constant PROCESS_ALERT => 'process_alert';
  1         1  
  1         34  
14 1     1   5 use constant PROCESS_UPDATE => 'process_update';
  1         1  
  1         855  
15              
16             has alert_callback => sub { die "missing mandatory parameter 'alert_cb'" };
17             has backend => undef;
18             has minion => sub { die "missing mandatory parameter 'minion'" };
19             has name => 'memorator';
20              
21             sub _cleanup_alerts {
22 0     0     my ($self, $minion) = @_;
23 0   0       $minion //= $self->minion;
24              
25 0           my $backend = $self->backend;
26 0           my $log = $minion->app->log;
27              
28 0     0     my @stales = try { $backend->stale_mappings }
29 0     0     catch { $log->error("cleanup error: $_"); };
  0            
30              
31 0           for my $stale (@stales) {
32 0           my ($id, $eid, $jid) = @{$stale}{qw< id eid jid >};
  0            
33 0 0         if (! defined $id) {
34 0           $log->error('found stale with undefined id...');
35 0           next;
36             }
37             try {
38 0 0   0     my $log_jid = defined($jid) ? $jid : '*undef*';
39 0           $log->info("removing superseded job '$log_jid'");
40 0           $backend->remove_mapping($id);
41 0 0         if (my $job = $minion->job($jid)) {
42             $job->remove
43 0 0         if $job->info->{state} =~ m{\A(?: active | inactive )\z}mxs;
44             }
45             } ## end try
46             catch {
47 0     0     $log->error("cleanup of id<$id>/eid<$eid>/jid<$jid> error: $_");
48 0           };
49             } ## end for my $href (@stales)
50              
51 0           return;
52             } ## end sub _cleanup_alerts
53              
54             sub _minion2backend {
55 0     0     my $self = shift;
56 0           my $mb = $self->minion->backend;
57 0           (my $dbtech = ref $mb) =~ s{.*::}{}mxs;
58 0           my $mdb = $mb->can(lc($dbtech))->($mb);
59 0           my $classname = __PACKAGE__ . '::Backend::' . ref($mdb);
60 0           return use_module($classname)->new(mojodb => $mdb, name => $self->name);
61             } ## end sub _minion2backend
62              
63             sub _local_name {
64 0     0     my ($self, $suffix) = @_;
65 0           return Memorator::Util::local_name($self->name, $suffix);
66             }
67              
68             sub new {
69 0     0 1   my $package = shift;
70 0           my $self = $package->SUPER::new(@_);
71              
72 0 0         $self->backend($self->_minion2backend) unless $self->backend;
73 0           $self->backend->ensure_table;
74              
75 0           my $minion = $self->minion;
76             $minion->add_task($self->_local_name(PROCESS_UPDATE) =>
77 0     0     sub { $self->_process_update(@_) });
  0            
78             $minion->add_task($self->_local_name(PROCESS_ALERT) =>
79 0     0     sub { $self->_process_alert(@_) });
  0            
80              
81 0           return $self;
82             } ## end sub new
83              
84             sub _process_alert {
85 0     0     my ($self, $job, $eid) = @_;
86 0           my $backend = $self->backend;
87              
88             # find mapping, fail fast if not present/obsoleted/superseded
89 0 0         my $e2j = $backend->mapping_between($eid, $job->id)
90             or return $job->fail;
91              
92             # here this job is entitled to send the alert for this eid
93 0           $self->alert_callback->($eid);
94              
95             # now passivate the mapping and do a general cleanup
96 0           $backend->deactivate_mapping($e2j->{id});
97 0           $self->_cleanup_alerts($job->minion);
98              
99 0           return;
100             } ## end sub _process_alert
101              
102             sub _process_update {
103 0     0     my ($self, $job, $alert) = @_;
104 0           return $self->set_alert($alert, $job->minion);
105             }
106              
107             sub remove_alert {
108 0     0 1   my ($self, $id, $minion) = @_;
109 0 0         $self->backend->remove_mapping(ref($id) ? $id->{id} : $id);
110 0           $self->_cleanup_alerts($minion);
111 0           return;
112             }
113              
114             sub set_alert {
115 0     0 1   my ($self, $alert, $minion) = @_;
116 0   0       $minion //= $self->minion;
117 0           my ($eid, $epoch, $attempts) = @{$alert}{qw< id epoch attempts >};
  0            
118 0   0       $attempts //= ATTEMPTS;
119              
120 0 0         if (defined $epoch) {
121 0           my $now = time;
122 0 0         my $delay = ($epoch > $now) ? ($epoch - $now) : 0;
123              
124 0           my $task = $self->_local_name(PROCESS_ALERT);
125 0           $minion->app->log->debug("enqueuing $task in ${delay}s");
126 0           my $jid = $minion->enqueue(
127             $task => [$eid],
128             {delay => $delay, attempts => $attempts}
129             );
130              
131             # record for future mapping
132 0           $self->backend->add_mapping($eid, $jid);
133             }
134             else { # remove alert
135 0           $self->backend->remove_mapping($eid);
136             }
137              
138             # whatever happened, cleanup
139 0           $self->_cleanup_alerts($minion); # never fails
140 0           return $self;
141             } ## end sub set_alert
142              
143             1;