1
1
package edu .unc .lib .deposit .work ;
2
2
3
3
import java .io .File ;
4
+ import java .io .IOException ;
4
5
import java .text .MessageFormat ;
5
6
import java .util .Arrays ;
7
+ import java .util .HashMap ;
8
+ import java .util .HashSet ;
6
9
import java .util .List ;
7
10
import java .util .Map ;
8
11
import java .util .Set ;
20
23
import net .greghaines .jesque .worker .WorkerListener ;
21
24
import net .greghaines .jesque .worker .WorkerPool ;
22
25
26
+ import org .codehaus .jackson .JsonNode ;
27
+ import org .codehaus .jackson .map .ObjectMapper ;
23
28
import org .slf4j .Logger ;
24
29
import org .slf4j .LoggerFactory ;
25
30
import org .springframework .beans .factory .annotation .Autowired ;
26
31
32
+ import redis .clients .jedis .Jedis ;
33
+ import redis .clients .jedis .JedisPool ;
27
34
import edu .unc .lib .deposit .CleanupDepositJob ;
28
35
import edu .unc .lib .deposit .PrepareResubmitJob ;
29
36
import edu .unc .lib .deposit .fcrepo3 .IngestDeposit ;
36
43
import edu .unc .lib .deposit .normalize .UnpackDepositJob ;
37
44
import edu .unc .lib .deposit .normalize .VocabularyEnforcementJob ;
38
45
import edu .unc .lib .deposit .validate .PackageIntegrityCheckJob ;
46
+ import edu .unc .lib .deposit .validate .ValidateFileAvailabilityJob ;
39
47
import edu .unc .lib .deposit .validate .ValidateMODS ;
40
48
import edu .unc .lib .deposit .validate .VirusScanJob ;
41
- import edu .unc .lib .deposit .validate .ValidateFileAvailabilityJob ;
42
49
import edu .unc .lib .dl .fedora .FedoraTimeoutException ;
43
50
import edu .unc .lib .dl .util .DepositConstants ;
44
51
import edu .unc .lib .dl .util .DepositStatusFactory ;
45
52
import edu .unc .lib .dl .util .JobStatusFactory ;
46
53
import edu .unc .lib .dl .util .PackagingType ;
54
+ import edu .unc .lib .dl .util .RedisWorkerConstants ;
47
55
import edu .unc .lib .dl .util .RedisWorkerConstants .DepositAction ;
48
56
import edu .unc .lib .dl .util .RedisWorkerConstants .DepositField ;
49
57
import edu .unc .lib .dl .util .RedisWorkerConstants .DepositState ;
@@ -72,6 +80,9 @@ public class DepositSupervisor implements WorkerListener {
72
80
@ Autowired
73
81
private WorkerPool cdrMetsDepositWorkerPool ;
74
82
83
+ @ Autowired
84
+ private JedisPool jedisPool ;
85
+
75
86
@ Autowired
76
87
private DepositEmailHandler depositEmailHandler ;
77
88
@@ -137,6 +148,9 @@ public void init() {
137
148
}
138
149
139
150
public void start () {
151
+ // Repopulate the queue
152
+ requeueAll ();
153
+
140
154
LOG .info ("Starting deposit checks and worker pool" );
141
155
if (timer != null )
142
156
return ;
@@ -225,15 +239,53 @@ public void run() {
225
239
LOG .info ("Starting deposit workers" );
226
240
cdrMetsDepositWorkerPool .run ();
227
241
}
228
-
229
- // Repopulate the queue
230
- requeueAll ();
242
+ }
243
+
244
+ private Map <String , Set <String >> getQueuedDepositsWithJobs () {
245
+ Map <String , Set <String >> depositMap = new HashMap <>();
246
+ addQueuedDeposits (
247
+ RedisWorkerConstants .RESQUE_QUEUE_PREFIX + RedisWorkerConstants .DEPOSIT_PREPARE_QUEUE , depositMap );
248
+ addQueuedDeposits (
249
+ RedisWorkerConstants .RESQUE_QUEUE_PREFIX + RedisWorkerConstants .DEPOSIT_DELAYED_QUEUE , depositMap );
250
+ addQueuedDeposits (
251
+ RedisWorkerConstants .RESQUE_QUEUE_PREFIX + RedisWorkerConstants .DEPOSIT_CDRMETS_QUEUE , depositMap );
252
+ return depositMap ;
253
+ }
254
+
255
+ private void addQueuedDeposits (String queueName , Map <String , Set <String >> depositMap ) {
256
+ Jedis jedis = jedisPool .getResource ();
257
+ Set <String > queue ;
258
+ try {
259
+ queue = jedis .zrange (queueName , 0 , -1 );
260
+ } catch (Exception e ) {
261
+ // Resque seems to sometimes switch the type of the queue
262
+ LOG .warn ("Redis did not return a zset for {}, trying to retrieve as a list" , queueName , e );
263
+ queue = new HashSet <>(jedis .lrange (queueName , 0 , -1 ));
264
+ }
265
+
266
+ ObjectMapper mapper = new ObjectMapper ();
267
+ for (String entry : queue ) {
268
+ try {
269
+ JsonNode node = mapper .readTree (entry );
270
+ String depositId = node .get ("args" ).get (1 ).asText ();
271
+ Set <String > jobs = depositMap .get (depositId );
272
+ if (jobs == null ) {
273
+ jobs = new HashSet <>();
274
+ depositMap .put (depositId , jobs );
275
+ }
276
+ jobs .add (node .get ("class" ).asText ());
277
+ } catch (IOException e ) {
278
+ LOG .error ("Failed to parse deposit job from resque" , e );
279
+ }
280
+ }
231
281
}
232
282
233
283
/**
234
284
* Add jobs previously running or queued back to the queue
235
285
*/
236
286
private void requeueAll () {
287
+
288
+ Map <String , Set <String >> depositSet = getQueuedDepositsWithJobs ();
237
289
Set <Map <String , String >> depositStatuses = depositStatusFactory .getAll ();
238
290
239
291
LOG .info ("Repopulating the deposit queue, {} items in backlog" , depositStatuses .size ());
@@ -246,7 +298,16 @@ private void requeueAll() {
246
298
// Job may have been locked to a particular supervisor depend on when it was interrupted
247
299
depositStatusFactory .removeSupervisorLock (uuid );
248
300
// Inform supervisor to resume this deposit from where it left off
249
- depositStatusFactory .setActionRequest (uuid , DepositAction .resume );
301
+ if (depositSet .containsKey (uuid )) {
302
+ // If the job is queued but the job it is waiting on is a cleanup, then it is finished
303
+ if (depositSet .get (uuid ).contains (CleanupDepositJob .class .getName ())) {
304
+ depositStatusFactory .setState (uuid , DepositState .finished );
305
+ } else {
306
+ LOG .debug ("Skipping resumption of deposit {} because it already is in the queue" , uuid );
307
+ }
308
+ } else {
309
+ depositStatusFactory .setActionRequest (uuid , DepositAction .resume );
310
+ }
250
311
}
251
312
}
252
313
@@ -257,7 +318,21 @@ private void requeueAll() {
257
318
258
319
depositStatusFactory .removeSupervisorLock (uuid );
259
320
// Re-register as a new deposit
260
- depositStatusFactory .setActionRequest (uuid , DepositAction .register );
321
+ if (depositSet .containsKey (uuid )) {
322
+ if (depositSet .get (uuid ).contains (CleanupDepositJob .class .getName ())) {
323
+ depositStatusFactory .setState (uuid , DepositState .finished );
324
+ } else {
325
+ LOG .debug ("Skipping resumption of queued deposit {} because it already is in the queue" , uuid );
326
+ }
327
+ } else {
328
+ List <String > successfulJobs = jobStatusFactory .getSuccessfulJobNames (uuid );
329
+ if (successfulJobs != null && successfulJobs .size () > 0 ) {
330
+ // Queued but had already performed some jobs, so this is a resumption rather than new deposit
331
+ depositStatusFactory .setActionRequest (uuid , DepositAction .resume );
332
+ } else {
333
+ depositStatusFactory .setActionRequest (uuid , DepositAction .register );
334
+ }
335
+ }
261
336
}
262
337
}
263
338
}
@@ -607,9 +682,18 @@ private void resumeDeposit(String uuid, Map<String, String> status, long delay)
607
682
// Clear out the previous failed job if there was one
608
683
jobStatusFactory .clearStale (uuid );
609
684
depositStatusFactory .deleteField (uuid , DepositField .errorMessage );
685
+
686
+ boolean enqueueNext = true ;
687
+ if (DepositState .paused .name ().equals (status .get (DepositField .state .name ()))) {
688
+ Map <String , Set <String >> depositSet = getQueuedDepositsWithJobs ();
689
+ enqueueNext = !depositSet .containsKey (uuid );
690
+ LOG .info ("Resuming from paused state. {} will enqueue a new job {}" , uuid , enqueueNext );
691
+ }
610
692
611
- List <String > successfulJobs = jobStatusFactory .getSuccessfulJobNames (uuid );
612
- queueNextJob (null , uuid , status , successfulJobs , delay );
693
+ if (enqueueNext ) {
694
+ List <String > successfulJobs = jobStatusFactory .getSuccessfulJobNames (uuid );
695
+ queueNextJob (null , uuid , status , successfulJobs , delay );
696
+ }
613
697
614
698
depositStatusFactory .setState (uuid , DepositState .queued );
615
699
} catch (DepositFailedException e ) {
0 commit comments