From 29738364fb731e89a1d9a4b91a5bd69333f7e2a0 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Thu, 26 Aug 2021 12:38:33 -0400 Subject: [PATCH] ResultSet::TaskRetries: add get_seconds_to_next_retry Get the number of seconds before the next retriable task is ready. This number is specifically intended to be used as a timeout, where `undef` means never time out. --- src/lib/Hydra/Schema/ResultSet/TaskRetries.pm | 41 +++++++++++++++++ t/Schema/ResultSet/TaskRetries.t | 45 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/lib/Hydra/Schema/ResultSet/TaskRetries.pm create mode 100644 t/Schema/ResultSet/TaskRetries.t diff --git a/src/lib/Hydra/Schema/ResultSet/TaskRetries.pm b/src/lib/Hydra/Schema/ResultSet/TaskRetries.pm new file mode 100644 index 00000000..86d16b9f --- /dev/null +++ b/src/lib/Hydra/Schema/ResultSet/TaskRetries.pm @@ -0,0 +1,41 @@ +package Hydra::Schema::ResultSet::TaskRetries; + +use strict; +use warnings; +use utf8; +use base 'DBIx::Class::ResultSet'; +use List::Util qw(max); + +=head2 get_seconds_to_next_retry + +Query the database to identify how soon the next retryable task is due +for being attempted again. + +If there are no tasks to be reattempted it returns undef. + +If a task's scheduled retry has passed, it returns 0. + +Otherwise, returns the number of seconds from now to look for work. + +=cut +sub get_seconds_to_next_retry { + my ($self) = @_; + + my $next_retry = $self->search( + {}, # any task + { + order_by => { + -asc => 'retry_at' + }, + rows => 1, + } + )->get_column('retry_at')->first; + + if (defined($next_retry)) { + return max(0, $next_retry - time()); + } else { + return undef; + } +} + +1; diff --git a/t/Schema/ResultSet/TaskRetries.t b/t/Schema/ResultSet/TaskRetries.t new file mode 100644 index 00000000..237ef20a --- /dev/null +++ b/t/Schema/ResultSet/TaskRetries.t @@ -0,0 +1,45 @@ +use strict; +use warnings; +use Setup; + +my %ctx = test_init(); + +require Hydra::Schema; +require Hydra::Model::DB; + +use Test2::V0; + +my $db = Hydra::Model::DB->new; +hydra_setup($db); + +my $taskretries = $db->resultset('TaskRetries'); + +subtest "get_seconds_to_next_retry" => sub { + subtest "Without any records in the database" => sub { + is($taskretries->get_seconds_to_next_retry(), undef, "Without any records our next retry moment is forever away."); + }; + + subtest "With only tasks whose retry timestamps are in the future" => sub { + $taskretries->create({ + channel => "bogus", + pluginname => "bogus", + payload => "bogus", + attempts => 1, + retry_at => time() + 100, + }); + is($taskretries->get_seconds_to_next_retry(), within(100, 2), "We should retry in roughly 100 seconds"); + }; + + subtest "With tasks whose retry timestamp are in the past" => sub { + $taskretries->create({ + channel => "bogus", + pluginname => "bogus", + payload => "bogus", + attempts => 1, + retry_at => time() - 100, + }); + is($taskretries->get_seconds_to_next_retry(), 0, "We should retry immediately"); + } +}; + +done_testing;