File Coverage

blib/lib/Argon/Tracker.pm
Criterion Covered Total %
statement 49 49 100.0
branch 8 12 66.6
condition n/a
subroutine 16 16 100.0
pod 7 7 100.0
total 80 84 95.2


line stmt bran cond sub pod time code
1             package Argon::Tracker;
2             # ABSTRACT: Internal class used to track node capacity
3             $Argon::Tracker::VERSION = '0.18';
4              
5 2     2   574 use strict;
  2         4  
  2         62  
6 2     2   11 use warnings;
  2         5  
  2         59  
7 2     2   15 use Carp;
  2         6  
  2         166  
8 2     2   18 use Moose;
  2         7  
  2         19  
9 2     2   18666 use List::Util qw(sum0);
  2         27  
  2         183  
10 2     2   615 use Time::HiRes qw(time);
  2         1465  
  2         17  
11 2     2   784 use Argon::Util qw(param);
  2         6  
  2         1461  
12              
13              
14             has length => (
15             is => 'rw',
16             isa => 'Int',
17             default => 20,
18             );
19              
20              
21             has capacity => (
22             is => 'rw',
23             isa => 'Int',
24             default => 0,
25             traits => ['Counter'],
26             handles => {
27             add_capacity => 'inc',
28             remove_capacity => 'dec',
29             },
30             );
31              
32             has started => (
33             is => 'rw',
34             isa => 'HashRef[Num]',
35             default => sub {{}},
36             traits => ['Hash'],
37             handles => {
38             track => 'set',
39             untrack => 'delete',
40             start_time => 'get',
41             is_tracked => 'exists',
42             assigned => 'count',
43             },
44             );
45              
46             has history => (
47             is => 'rw',
48             isa => 'ArrayRef[Num]',
49             default => sub {[]},
50             traits => ['Array'],
51             handles => {
52             record => 'push',
53             record_count => 'count',
54             prune_records => 'shift',
55             },
56             );
57              
58             has avg_time => (
59             is => 'rw',
60             isa => 'Num',
61             default => 0,
62             );
63              
64              
65 36     36 1 2159 sub available_capacity { $_[0]->capacity - $_[0]->assigned }
66 28     28 1 133 sub has_capacity { $_[0]->available_capacity > 0 }
67 3     3 1 154 sub load { ($_[0]->assigned + 1) * $_[0]->avg_time }
68              
69              
70             sub age {
71 3     3 1 9 my ($self, $msg) = @_;
72 3 50       71 return unless $self->is_tracked($msg->id);
73 3         109 time - $self->start_time($msg->id);
74             }
75              
76              
77             sub start {
78 20     20 1 2892 my ($self, $msg) = @_;
79 20 100       113 croak 'no capacity' unless $self->has_capacity;
80 18 50       2668 croak "msg id $msg->id is already tracked" if $self->is_tracked($msg->id);
81 18         875 $self->track($msg->id, time);
82 18         1804 $self->assigned;
83             }
84              
85              
86             sub finish {
87 18     18 1 788 my ($self, $msg) = @_;
88 18 100       1080 croak "msg id $msg->id is not tracked" unless $self->is_tracked($msg->id);
89 17         81 --$self->{assigned};
90 17         1044 $self->_add_to_history(time - $self->untrack($msg->id));
91 17         101 $self->_update_avg_time;
92             }
93              
94              
95             sub touch {
96 1     1 1 5 my ($self, $msg) = @_;
97 1 50       39 croak "msg id $msg->id is not tracked" unless $self->is_tracked($msg->id);
98 1         42 $self->track($msg->id, time);
99             }
100              
101             sub _add_to_history {
102 17     17   137 my ($self, $taken) = @_;
103 17         1297 $self->record($taken);
104 17         999 while ($self->record_count > $self->length) {
105 3         320 $self->prune_records;
106             }
107             }
108              
109             sub _update_avg_time {
110 17     17   48 my $self = shift;
111 17         45 my $total = sum0 @{$self->{history}};
  17         138  
112 17 50       119 $self->{avg_time} = $total == 0 ? 0 : $total / @{$self->{history}};
  17         220  
113             }
114              
115             __PACKAGE__->meta->make_immutable;
116              
117             1;
118              
119             __END__
120              
121             =pod
122              
123             =encoding UTF-8
124              
125             =head1 NAME
126              
127             Argon::Tracker - Internal class used to track node capacity
128              
129             =head1 VERSION
130              
131             version 0.18
132              
133             =head1 DESCRIPTION
134              
135             An internally used class that tracks capacity of worker nodes.
136              
137             =head1 ATTRIBUTES
138              
139             =head2 length
140              
141             The number of completed past transactions used to calculate load.
142              
143             =head2 capacity
144              
145             The capacity as the sum of tracked worker capacities.
146              
147             =head1 METHODS
148              
149             =head2 add_capacity
150              
151             Increment capacity by the supplied value.
152              
153             =head2 remove_capacity
154              
155             Decrement capacity by the supplied value.
156              
157             =head2 available_capacity
158              
159             Returns the number of task slots available; equivalent to the total capacity
160             less the number of actively tracked tasks.
161              
162             =head2 has_capacity
163              
164             Returns true if the L</available_capacity> is greater than zero.
165              
166             =head2 load
167              
168             Estimates and returns the time required to complete one more than the number of
169             currently tracked tasks.
170              
171             =head2 age
172              
173             Returns the number of seconds since the tracker began tracking the supplied
174             L<Argon::Message>.
175              
176             =head2 start
177              
178             Begins tracking an L<Argon::Message>.
179              
180             =head2 finish
181              
182             Completes tracking on an L<Argon::Message>.
183              
184             =head2 touch
185              
186             Resets the start time on an L<Argon::Message>.
187              
188             =head1 AUTHOR
189              
190             Jeff Ober <sysread@fastmail.fm>
191              
192             =head1 COPYRIGHT AND LICENSE
193              
194             This software is copyright (c) 2017 by Jeff Ober.
195              
196             This is free software; you can redistribute it and/or modify it under
197             the same terms as the Perl 5 programming language system itself.
198              
199             =cut