View Javadoc
1   /*
2    * Copyright (C) 2024 B3Partners B.V.
3    *
4    * SPDX-License-Identifier: MIT
5    */
6   package org.tailormap.api.scheduling;
7   
8   import java.lang.invoke.MethodHandles;
9   import java.time.Instant;
10  import org.quartz.DisallowConcurrentExecution;
11  import org.quartz.InterruptableJob;
12  import org.quartz.JobDataMap;
13  import org.quartz.JobDetail;
14  import org.quartz.JobExecutionContext;
15  import org.quartz.JobExecutionException;
16  import org.quartz.PersistJobDataAfterExecution;
17  import org.quartz.UnableToInterruptJobException;
18  import org.slf4j.Logger;
19  import org.slf4j.LoggerFactory;
20  import org.springframework.lang.NonNull;
21  import org.springframework.scheduling.quartz.QuartzJobBean;
22  
23  /** POC task for testing purposes, this is a task that can be interrupted. */
24  @DisallowConcurrentExecution
25  @PersistJobDataAfterExecution
26  public class InterruptablePocTask extends QuartzJobBean implements Task, InterruptableJob {
27  
28    private static final Logger logger =
29        LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
30  
31    private boolean interrupted = false;
32  
33    private String description;
34  
35    @Override
36    public void interrupt() throws UnableToInterruptJobException {
37      logger.info("Interrupting POC task");
38      interrupted = true;
39    }
40  
41    @Override
42    protected void executeInternal(@NonNull JobExecutionContext context)
43        throws JobExecutionException {
44  
45      final JobDetail jobDetail = context.getJobDetail();
46  
47      // NOTE: This immutable map is a snapshot of the job data maps at the time of the job execution.
48      final JobDataMap mergedJobDataMap = context.getMergedJobDataMap();
49  
50      // NOTE: This map is mutable and can be used to store job data.
51      final JobDataMap jobDataMap = jobDetail.getJobDataMap();
52  
53      logger.debug(
54          "executing POC task {}:{}, details: {}",
55          jobDetail.getKey().getGroup(),
56          jobDetail.getKey().getName(),
57          mergedJobDataMap.getWrappedMap());
58  
59      try {
60        for (int i = 0; i < 110; i += 10) {
61          // Simulate some work for a random period of time
62          long workingTime = (long) (Math.random() * 5000);
63          logger.debug("Working for {} ms", workingTime);
64          Thread.sleep(workingTime);
65          logger.debug("Interruptable POC task is at {}%", i);
66          context.setResult("Interruptable POC task is at %d%%".formatted(i));
67  
68          if (interrupted) {
69            logger.debug("Interruptable POC task interrupted at {}%", Instant.now());
70            jobDataMap.put(
71                Task.LAST_RESULT_KEY,
72                "Interruptable POC task interrupted after %d%% iterations".formatted(i));
73            jobDataMap.put("lastExecutionFinished", null);
74            context.setResult(
75                "Interruptable POC task interrupted after %d%% iterations".formatted(i));
76            // bail out after interruption
77            return;
78          }
79  
80          int executions = (1 + (int) mergedJobDataMap.getOrDefault("executions", 0));
81          jobDataMap.put("executions", executions);
82          jobDataMap.put("lastExecutionFinished", Instant.now());
83          jobDataMap.put(Task.LAST_RESULT_KEY, "Interruptable POC task executed successfully");
84          context.setResult("Interruptable POC task executed successfully");
85        }
86      } catch (InterruptedException e) {
87        logger.error("Thread interrupted", e);
88      }
89    }
90  
91    @Override
92    public TaskType getType() {
93      return TaskType.INTERRUPTABLEPOC;
94    }
95  
96    @Override
97    public String getDescription() {
98      return description;
99    }
100 
101   @Override
102   public void setDescription(String description) {
103     this.description = description;
104   }
105 }