Frédéric Demians
dcfa31d5dc
Bug 11395 uses the session to store the report sent to the interface (update on biblio XX OK, etc.). If the session is stored in mysql, the max size of the sessions.a_session will be reached easily (TEXT field). To reproduce: 0/ Set SessionStorage to 'mysql' 1/ Create a file with 500 biblionumbers: mysql -e "select biblionumber from biblio limit 500;" | tail -n 500 > /tmp/biblionumbers.txt 2/ Define a marc modification template (something like "delete field 99$9" is nice) 3/ Load the /tmp/biblionumbers.txt in the batch biblio modification tool 4/ Repeat 3 You will get: Syck parser (line 1534, column 6): syntax error at /usr/lib/i386-linux-gnu/perl5/5.20/YAML/Syck.pm line 75. None Koha page is reachable. It comes from get_template_and_user > checkauth > get_session > l.1595 $session = new CGI::Session("driver:MySQL;serializer:yaml;id:md5", $sessionID, {Handle=>$dbh}); 5/ Get your sessionID contained in your CGISESSID cookie Have a look at the value a_session in the sessions table: mysql> select a_session from sessions where id="YOUR_SESSIONID"; You should see that the yaml is not correctly ended. The size of the DB field has been reached and the yaml is truncated. Test plan: 0/ Delete your CGISESSID cookie 1/ Try to reproduce the previous issue 2/ After the second batch, have a look at the sessions table and confirm that only one job_$JOB_ID exist in the yaml Signed-off-by: Jonathan Druart <jonathan.druart@biblibre.com> NOTE: Nicely clears batch job session information. (2) is incorrect. This cleans up after a full run. Signed-off-by: Mark Tompsett <mtompset@hotmail.com> Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
331 lines
6.2 KiB
Perl
331 lines
6.2 KiB
Perl
package C4::BackgroundJob;
|
|
|
|
# Copyright (C) 2007 LibLime
|
|
# Galen Charlton <galen.charlton@liblime.com>
|
|
#
|
|
# 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 <http://www.gnu.org/licenses>.
|
|
|
|
use strict;
|
|
#use warnings; FIXME - Bug 2505
|
|
use C4::Context;
|
|
use C4::Auth qw/get_session/;
|
|
use Digest::MD5;
|
|
|
|
use vars qw($VERSION);
|
|
|
|
BEGIN {
|
|
# set the version for version checking
|
|
$VERSION = 3.07.00.049;
|
|
}
|
|
|
|
=head1 NAME
|
|
|
|
C4::BackgroundJob - manage long-running jobs
|
|
initiated from the web staff interface
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
# start tracking a job
|
|
my $job = C4::BackgroundJob->new($sessionID, $job_name, $job_invoker, $num_work_units);
|
|
my $jobID = $job->id();
|
|
$job->progress($work_units_processed);
|
|
$job->finish($job_result_hashref);
|
|
|
|
# get status and results of a job
|
|
my $job = C4::BackgroundJob->fetch($sessionID, $jobID);
|
|
my $max_work_units = $job->size();
|
|
my $work_units_processed = $job->progress();
|
|
my $job_status = $job->status();
|
|
my $job_name = $job->name();
|
|
my $job_invoker = $job->invoker();
|
|
my $results_hashref = $job->results();
|
|
|
|
This module manages tracking the progress and results
|
|
of (potentially) long-running jobs initiated from
|
|
the staff user interface. Such jobs can include
|
|
batch MARC and patron record imports.
|
|
|
|
=head1 METHODS
|
|
|
|
=head2 new
|
|
|
|
my $job = C4::BackgroundJob->new($sessionID, $job_name, $job_invoker, $num_work_units);
|
|
|
|
Create a new job object and set its status to 'running'. C<$num_work_units>
|
|
should be a number representing the size of the job; the units of the
|
|
job size are up to the caller and could be number of records,
|
|
number of bytes, etc.
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
my ($sessionID, $job_name, $job_invoker, $num_work_units) = @_;
|
|
|
|
my $self = {};
|
|
$self->{'sessionID'} = $sessionID;
|
|
$self->{'name'} = $job_name;
|
|
$self->{'invoker'} = $job_invoker;
|
|
$self->{'size'} = $num_work_units;
|
|
$self->{'progress'} = 0;
|
|
$self->{'status'} = "running";
|
|
$self->{'jobID'} = Digest::MD5::md5_hex(Digest::MD5::md5_hex(time().{}.rand().{}.$$));
|
|
$self->{'extra_values'} = {};
|
|
|
|
bless $self, $class;
|
|
$self->_serialize();
|
|
|
|
return $self;
|
|
}
|
|
|
|
# store object in CGI session
|
|
sub _serialize {
|
|
my $self = shift;
|
|
|
|
my $prefix = "job_" . $self->{'jobID'};
|
|
my $session = get_session($self->{'sessionID'});
|
|
$session->param($prefix, $self);
|
|
$session->flush();
|
|
}
|
|
|
|
=head2 id
|
|
|
|
my $jobID = $job->id();
|
|
|
|
Read-only accessor for job ID.
|
|
|
|
=cut
|
|
|
|
sub id {
|
|
my $self = shift;
|
|
return $self->{'jobID'};
|
|
}
|
|
|
|
=head2 name
|
|
|
|
my $name = $job->name();
|
|
$job->name($name);
|
|
|
|
Read/write accessor for job name.
|
|
|
|
=cut
|
|
|
|
sub name {
|
|
my $self = shift;
|
|
if (@_) {
|
|
$self->{'name'} = shift;
|
|
$self->_serialize();
|
|
} else {
|
|
return $self->{'name'};
|
|
}
|
|
}
|
|
|
|
=head2 invoker
|
|
|
|
my $invoker = $job->invoker();
|
|
i $job->invoker($invoker);
|
|
|
|
Read/write accessor for job invoker.
|
|
|
|
=cut
|
|
|
|
sub invoker {
|
|
my $self = shift;
|
|
if (@_) {
|
|
$self->{'invoker'} = shift;
|
|
$self->_serialize();
|
|
} else {
|
|
return $self->{'invoker'};
|
|
}
|
|
}
|
|
|
|
=head2 progress
|
|
|
|
my $progress = $job->progress();
|
|
$job->progress($progress);
|
|
|
|
Read/write accessor for job progress.
|
|
|
|
=cut
|
|
|
|
sub progress {
|
|
my $self = shift;
|
|
if (@_) {
|
|
$self->{'progress'} = shift;
|
|
$self->_serialize();
|
|
} else {
|
|
return $self->{'progress'};
|
|
}
|
|
}
|
|
|
|
=head2 status
|
|
|
|
my $status = $job->status();
|
|
|
|
Read-only accessor for job status.
|
|
|
|
=cut
|
|
|
|
sub status {
|
|
my $self = shift;
|
|
return $self->{'status'};
|
|
}
|
|
|
|
=head2 size
|
|
|
|
my $size = $job->size();
|
|
$job->size($size);
|
|
|
|
Read/write accessor for job size.
|
|
|
|
=cut
|
|
|
|
sub size {
|
|
my $self = shift;
|
|
if (@_) {
|
|
$self->{'size'} = shift;
|
|
$self->_serialize();
|
|
} else {
|
|
return $self->{'size'};
|
|
}
|
|
}
|
|
|
|
=head2 finish
|
|
|
|
$job->finish($results_hashref);
|
|
|
|
Mark the job as finished, setting its status to 'completed'.
|
|
C<$results_hashref> should be a reference to a hash containing
|
|
the results of the job.
|
|
|
|
=cut
|
|
|
|
sub finish {
|
|
my $self = shift;
|
|
my $results_hashref = shift;
|
|
$self->{'status'} = 'completed';
|
|
$self->{'results'} = $results_hashref;
|
|
$self->_serialize();
|
|
}
|
|
|
|
=head2 results
|
|
|
|
my $results_hashref = $job->results();
|
|
|
|
Retrieve the results of the current job. Returns undef
|
|
if the job status is not 'completed'.
|
|
|
|
=cut
|
|
|
|
sub results {
|
|
my $self = shift;
|
|
return unless $self->{'status'} eq 'completed';
|
|
return $self->{'results'};
|
|
}
|
|
|
|
=head2 fetch
|
|
|
|
my $job = C4::BackgroundJob->fetch($sessionID, $jobID);
|
|
|
|
Retrieve a job that has been serialized to the database.
|
|
Returns C<undef> if the job does not exist in the current
|
|
session.
|
|
|
|
=cut
|
|
|
|
sub fetch {
|
|
my $class = shift;
|
|
my $sessionID = shift;
|
|
my $jobID = shift;
|
|
|
|
my $session = get_session($sessionID);
|
|
my $prefix = "job_$jobID";
|
|
unless (defined $session->param($prefix)) {
|
|
return;
|
|
}
|
|
my $self = $session->param($prefix);
|
|
bless $self, $class;
|
|
return $self;
|
|
}
|
|
|
|
=head2 set
|
|
|
|
=over 4
|
|
|
|
=item $job->set($hashref);
|
|
|
|
=back
|
|
|
|
Set some variables into the hashref.
|
|
These variables can be retrieved using the get method.
|
|
|
|
=cut
|
|
|
|
sub set {
|
|
my ($self, $hashref) = @_;
|
|
while ( my ($k, $v) = each %$hashref ) {
|
|
$self->{extra_values}->{$k} = $v;
|
|
}
|
|
$self->_serialize();
|
|
return;
|
|
}
|
|
|
|
=head2 get
|
|
|
|
=over 4
|
|
|
|
=item $value = $job->get($key);
|
|
|
|
=back
|
|
|
|
Get a variable which has been previously stored with the set method.
|
|
|
|
=cut
|
|
|
|
sub get {
|
|
my ($self, $key) = @_;
|
|
return $self->{extra_values}->{$key};
|
|
}
|
|
|
|
|
|
=head2 clear
|
|
|
|
=over 4
|
|
|
|
=item $job->clear();
|
|
|
|
=back
|
|
|
|
Clear the job from the current session.
|
|
|
|
=cut
|
|
|
|
sub clear {
|
|
my $self = shift;
|
|
get_session($self->{sessionID})->clear('job_' . $self->{jobID});
|
|
}
|
|
|
|
|
|
1;
|
|
__END__
|
|
|
|
=head1 AUTHOR
|
|
|
|
Koha Development Team <http://koha-community.org/>
|
|
|
|
Galen Charlton <galen.charlton@liblime.com>
|
|
|
|
=cut
|