Introduce sth caching to Letters.pm
[koha.git] / C4 / BackgroundJob.pm
1 package C4::BackgroundJob;
2
3 # Copyright (C) 2007 LibLime
4 # Galen Charlton <galen.charlton@liblime.com>
5 #
6 # This file is part of Koha.
7 #
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 2 of the License, or (at your option) any later
11 # version.
12 #
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along with
18 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 # Suite 330, Boston, MA  02111-1307 USA
20
21 use strict;
22 use C4::Context;
23 use C4::Auth qw/get_session/;
24 use Digest::MD5;
25
26 use vars qw($VERSION);
27
28 BEGIN {
29         # set the version for version checking
30         $VERSION = 3.00;
31 }
32
33 =head1 NAME
34
35 C4::BackgroundJob - manage long-running jobs
36 initiated from the web staff interface
37
38 =head1 SYNOPSIS
39
40 =over 4
41
42 # start tracking a job
43 my $job = C4::BackgroundJob->new($sessionID, $job_name, $job_invoker, $num_work_units);
44 my $jobID = $job->id();
45 $job->progress($work_units_processed);
46 $job->finish($job_result_hashref);
47
48 # get status and results of a job
49 my $job = C4::BackgroundJob->fetch($sessionID, $jobID);
50 my $max_work_units = $job->size();
51 my $work_units_processed = $job->progress();
52 my $job_status = $job->status();
53 my $job_name = $job->name();
54 my $job_invoker = $job->invoker();
55 my $results_hashref = $job->results();
56
57 =back
58
59 This module manages tracking the progress and results
60 of (potentially) long-running jobs initiated from 
61 the staff user interface.  Such jobs can include
62 batch MARC and patron record imports.
63
64 =cut
65
66 =head1 METHODS
67
68 =cut
69
70 =head2 new
71
72 =over 4
73
74 my $job = C4::BackgroundJob->new($sessionID, $job_name, $job_invoker, $num_work_units);
75
76 =back
77
78 Create a new job object and set its status to 'running'.  C<$num_work_units>
79 should be a number representing the size of the job; the units of the
80 job size are up to the caller and could be number of records, 
81 number of bytes, etc.
82
83 =cut
84
85 sub new {
86     my $class = shift;
87     my ($sessionID, $job_name, $job_invoker, $num_work_units) = @_;
88
89     my $self = {};
90     $self->{'sessionID'} = $sessionID;
91     $self->{'name'} = $job_name;
92     $self->{'invoker'} = $job_invoker;
93     $self->{'size'} = $num_work_units;
94     $self->{'progress'} = 0;
95     $self->{'status'} = "running";
96     $self->{'jobID'} = Digest::MD5::md5_hex(Digest::MD5::md5_hex(time().{}.rand().{}.$$));
97
98     bless $self, $class;
99     $self->_serialize();
100
101     return $self;
102 }
103
104 # store object in CGI session
105 sub _serialize {
106     my $self = shift;
107
108     my $prefix = "job_" . $self->{'jobID'};
109     my $session = get_session($self->{'sessionID'});
110     $session->param($prefix, $self);
111     $session->flush();
112 }
113
114 =head2 id
115
116 =over 4
117
118 my $jobID = $job->id();
119
120 =back
121
122 Read-only accessor for job ID.
123
124 =cut
125
126 sub id {
127     my $self = shift;
128     return $self->{'jobID'};
129 }
130
131 =head2 name
132
133 =over 4
134
135 my $name = $job->name();
136 $job->name($name);
137
138 =back
139
140 Read/write accessor for job name.
141
142 =cut
143
144 sub name {
145     my $self = shift;
146     if (@_) {
147         $self->{'name'} = shift;
148         $self->_serialize();
149     } else {
150         return $self->{'name'};
151     }
152 }
153
154 =head2 invoker
155
156 =over 4
157
158 my $invoker = $job->invoker();
159 $job->invoker($invoker);
160
161 =back
162
163 Read/write accessor for job invoker.
164
165 =cut
166
167 sub invoker {
168     my $self = shift;
169     if (@_) {
170         $self->{'invoker'} = shift;
171         $self->_serialize();
172     } else {
173         return $self->{'invoker'};
174     }
175 }
176
177 =head2 progress
178
179 =over 4
180
181 my $progress = $job->progress();
182 $job->progress($progress);
183
184 =back
185
186 Read/write accessor for job progress.
187
188 =cut
189
190 sub progress {
191     my $self = shift;
192     if (@_) {
193         $self->{'progress'} = shift;
194         $self->_serialize();
195     } else {
196         return $self->{'progress'};
197     }
198 }
199
200 =head2 status
201
202 =over 4
203
204 my $status = $job->status();
205
206 =back
207
208 Read-only accessor for job status.
209
210 =cut
211
212 sub status {
213     my $self = shift;
214     return $self->{'status'};
215 }
216
217 =head2 size
218
219 =over 4
220
221 my $size = $job->size();
222 $job->size($size);
223
224 =back
225
226 Read/write accessor for job size.
227
228 =cut
229
230 sub size {
231     my $self = shift;
232     if (@_) {
233         $self->{'size'} = shift;
234         $self->_serialize();
235     } else {
236         return $self->{'size'};
237     }
238 }
239
240 =head2 finish
241
242 =over 4
243
244 $job->finish($results_hashref);
245
246 =back
247
248 Mark the job as finished, setting its status to 'completed'.
249 C<$results_hashref> should be a reference to a hash containing
250 the results of the job.
251
252 =cut
253
254 sub finish {
255     my $self = shift;
256     my $results_hashref = shift;
257     $self->{'status'} = 'completed';
258     $self->{'results'} = $results_hashref;
259     $self->_serialize();
260 }
261
262 =head2 results
263
264 =over 4
265
266 my $results_hashref = $job->results();
267
268 =back
269
270 Retrieve the results of the current job.  Returns undef 
271 if the job status is not 'completed'.
272
273 =cut
274
275 sub results {
276     my $self = shift;
277     return undef unless $self->{'status'} eq 'completed';
278     return $self->{'results'};
279 }
280
281 =head2 fetch
282
283 =over 4
284
285 my $job = C4::BackgroundJob->fetch($sessionID, $jobID);
286
287 =back
288
289 Retrieve a job that has been serialized to the database. 
290 Returns C<undef> if the job does not exist in the current 
291 session.
292
293 =cut
294
295 sub fetch {
296     my $class = shift;
297     my $sessionID = shift;
298     my $jobID = shift;
299
300     my $session = get_session($sessionID);
301     my $prefix = "job_$jobID";
302     unless (defined $session->param($prefix)) {
303         return undef;
304     }
305     my $self = $session->param($prefix);
306     bless $self, $class;
307     return $self;
308 }
309
310 1;
311 __END__
312
313 =head1 AUTHOR
314
315 Koha Development Team <info@koha.org>
316
317 Galen Charlton <galen.charlton@liblime.com>
318
319 =cut