From 38fdd82d27f80d8265f97292b3e397f097281b04 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Fri, 25 Mar 2022 11:52:39 -0300 Subject: [PATCH] Bug 30360: Add helper methods to Koha::BackgroundJobs This patch adds some helper methods to ease writing background jobs, and also making it more consistent/solid. To test: 1. Apply this patch 2. Run: $ kshell k$ prove t/db_dependent/Koha/BackgroundJob.t => SUCCESS: Tests pass. The methods have the expected behaviour. 3. Sign off :-D Signed-off-by: Tomas Cohen Arazi Signed-off-by: David Nind Signed-off-by: Martin Renvoize --- Koha/BackgroundJob.pm | 70 +++++++++++++++++++++++++++++ Koha/Exceptions/BackgroundJob.pm | 60 +++++++++++++++++++++++++ t/db_dependent/Koha/BackgroundJob.t | 68 +++++++++++++++++++++++++++- 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 Koha/Exceptions/BackgroundJob.pm diff --git a/Koha/BackgroundJob.pm b/Koha/BackgroundJob.pm index 583ada7421..b6801cdf95 100644 --- a/Koha/BackgroundJob.pm +++ b/Koha/BackgroundJob.pm @@ -26,6 +26,7 @@ use C4::Context; use Koha::DateUtils qw( dt_from_string ); use Koha::Exceptions; use Koha::Plugins; +use Koha::Exceptions::BackgroundJob; use base qw( Koha::Object ); @@ -164,6 +165,75 @@ sub process { return $derived_class->process( $args ); } +=head3 start + + $self->start; + +Marks the job as started. + +=cut + +sub start { + my ($self) = @_; + + Koha::Exceptions::BackgroundJob::InconsistentStatus->throw( + current_status => $self->status, + expected_status => 'new' + ) unless $self->status eq 'new'; + + return $self->set( + { + started_on => \'NOW()', + progress => 0, + status => 'started', + } + )->store; +} + +=head3 step + + $self->step; + +Makes the job record a step has taken place. + +=cut + +sub step { + my ($self) = @_; + + Koha::Exceptions::BackgroundJob::InconsistentStatus->throw( + current_status => $self->status, + expected_status => 'started' + ) unless $self->status eq 'started'; + + # reached the end of the tasks already + Koha::Exceptions::BackgroundJob::StepOutOfBounds->throw() + unless $self->progress < $self->size; + + return $self->progress( $self->progress + 1 )->store; +} + +=head3 finish + + $self->finish; + +Makes the job record as finished. If the job status is I, it is kept. + +=cut + +sub finish { + my ( $self, $data ) = @_; + + $self->status('finished') unless $self->status eq 'cancelled'; + + return $self->set( + { + ended_on => \'NOW()', + data => encode_json($data), + } + )->store; +} + =head3 job_type Return the job type of the job. Must be a string. diff --git a/Koha/Exceptions/BackgroundJob.pm b/Koha/Exceptions/BackgroundJob.pm new file mode 100644 index 0000000000..65da5a3014 --- /dev/null +++ b/Koha/Exceptions/BackgroundJob.pm @@ -0,0 +1,60 @@ +package Koha::Exceptions::BackgroundJob; + +# This file is part of Koha. +# +# Koha 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. +# +# Koha 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 Koha; if not, see . + +use Modern::Perl; + +use Koha::Exception; + +use Exception::Class ( + + 'Koha::Exceptions::BackgroundJob' => { + isa => 'Koha::Exception', + }, + 'Koha::Exceptions::BackgroundJob::InconsistentStatus' => { + isa => 'Koha::Exceptions::BackgroundJob', + description => 'Status change requested but an invalid status found', + fields => ['current_status', 'expected_status'] + }, + 'Koha::Exceptions::BackgroundJob::StepOutOfBounds' => { + isa => 'Koha::Exceptions::BackgroundJob', + description => 'Cannot move progress forward' + }, +); + +=head1 NAME + +Koha::Exceptions::BackgroundJob - Base class for BackgroundJob exceptions + +=head1 Exceptions + +=head2 Koha::Exceptions::BackgroundJob + +Generic BackgroundJob exception + +=head2 Koha::Exceptions::BackgroundJob::InconsistentStatus + +Exception to be used when an action on an BackgroundJob requires the job to +be in an specific I, but it is not the case. + +=head2 Koha::Exceptions::BackgroundJob::StepOutOfBounds + +Exception to be used when the it is tried to advance one step in progress, but +the job size limit as been reached already. + +=cut + +1; diff --git a/t/db_dependent/Koha/BackgroundJob.t b/t/db_dependent/Koha/BackgroundJob.t index 04e78f956f..4801c68628 100755 --- a/t/db_dependent/Koha/BackgroundJob.t +++ b/t/db_dependent/Koha/BackgroundJob.t @@ -17,12 +17,15 @@ use Modern::Perl; -use Test::More tests => 2; +use Test::More tests => 3; +use Test::Exception; use Koha::Database; use Koha::BackgroundJobs; use Koha::BackgroundJob::BatchUpdateItem; +use JSON qw( decode_json ); + use t::lib::Mocks; use t::lib::TestBuilder; @@ -86,3 +89,66 @@ subtest 'enqueue() tests' => sub { $schema->storage->txn_rollback; }; + +subtest 'start(), step() and finish() tests' => sub { + + plan tests => 19; + + $schema->storage->txn_begin; + + # FIXME: This all feels we need to do it better... + my $job_id = Koha::BackgroundJob::BatchUpdateItem->new->enqueue( { record_ids => [ 1, 2 ] } ); + my $job = Koha::BackgroundJobs->find($job_id)->_derived_class; + + is( $job->started_on, undef, 'started_on not set yet' ); + is( $job->size, 2, 'Two steps' ); + + $job->start; + + isnt( $job->started_on, undef, 'started_on set' ); + is( $job->status, 'started' ); + is( $job->progress, 0, 'No progress yet' ); + + $job->step; + is( $job->progress, 1, 'First step' ); + $job->step; + is( $job->progress, 2, 'Second step' ); + throws_ok + { $job->step; } + 'Koha::Exceptions::BackgroundJob::StepOutOfBounds', + 'Tried to make a forbidden extra step'; + + is( $job->progress, 2, 'progress remains unchanged' ); + + my $data = { some => 'data' }; + + $job->status('cancelled')->store; + $job->finish( $data ); + + is( $job->status, 'cancelled', "'finish' leaves 'cancelled' untouched" ); + isnt( $job->ended_on, undef, 'ended_on set' ); + is_deeply( decode_json( $job->data ), $data ); + + $job->status('started')->store; + $job->finish( $data ); + + is( $job->status, 'finished' ); + isnt( $job->ended_on, undef, 'ended_on set' ); + is_deeply( decode_json( $job->data ), $data ); + + throws_ok + { $job->start; } + 'Koha::Exceptions::BackgroundJob::InconsistentStatus', + 'Exception thrown trying to start a finished job'; + + is( $@->expected_status, 'new' ); + + throws_ok + { $job->step; } + 'Koha::Exceptions::BackgroundJob::InconsistentStatus', + 'Exception thrown trying to start a finished job'; + + is( $@->expected_status, 'started' ); + + $schema->storage->txn_rollback; +}; -- 2.39.5