/*
 * Copyright (c) 2017 Nike, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.nike.cerberus.jobs;

import com.nike.cerberus.service.JobCoordinatorService;
import org.knowm.sundial.Job;
import org.knowm.sundial.exceptions.JobInterruptException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.util.concurrent.TimeUnit;

public abstract class LockingJob extends Job {

    protected final Logger log = LoggerFactory.getLogger(this.getClass());

    private JobCoordinatorService jobCoordinatorService;

    @Inject
    public void setJobCoordinatorService(JobCoordinatorService jobCoordinatorService) {
        this.jobCoordinatorService = jobCoordinatorService;
    }

    @Override
    public void doRun() throws JobInterruptException {
        String jobName = this.getJobContext().getJobName();
        if (! jobCoordinatorService.acquireLockToRunJob(jobName)) {
            log.info("Failed to acquire lock, another instance must be running the job. Job Name: {}", jobName);
            return;
        }

        log.info("Lock acquired for Job: {}, executing lockable code", jobName);
        try {
            executeLockableCode();
        } catch (Throwable t) {
            log.error("Failed to execute lockable job, releasing lock", t);
        }

        log.info("Attempting to release lock for Job: {}", jobName);
        boolean released = false;
        do {
            try {
                released = jobCoordinatorService.releaseLock(jobName);
                if (!released) { // Sometimes it takes multiple calls to release, why?
                    log.warn("Failed to release log, will retry after pause");
                    Thread.sleep(TimeUnit.SECONDS.toMillis(1));
                }
            } catch (InterruptedException | JobInterruptException e) {
                log.error("Pause interrupted while trying to release lock", e);
                throw new JobInterruptException();
            } catch (Throwable t) {
                log.error("Something went wrong trying to release lock retrying", t);
            }
        } while (! released);
        log.info("Lock released for Job: {}", jobName);
    }

    protected abstract void executeLockableCode();
}

@@ -1820,34 +1820,47 @@
 %22, t);%0A        %7D
-%0A%0A
+ finally %7B%0A    
         log.info
@@ -1904,32 +1904,36 @@
  %7B%7D%22, jobName);%0A
+    
         boolean 
@@ -1962,13 +1962,21 @@
     
+    
 do %7B%0A
+    
     
@@ -2005,16 +2005,20 @@
         
+  
+  
 released
@@ -2056,32 +2056,36 @@
 eLock(jobName);%0A
+    
                 
@@ -2171,24 +2171,28 @@
             
+   
+ 
 log.warn(%22Fa
@@ -2238,16 +2238,20 @@
 ause%22);%0A
+    
         
@@ -2314,32 +2314,36 @@
                 
+    
 %7D%0A            %7D 
@@ -2332,32 +2332,36 @@
   %7D%0A            
+ 
+   
 %7D catch (Interru
@@ -2378,32 +2378,8 @@
 ion 
-%7C JobInterruptException 
 e) %7B
@@ -2387,32 +2387,36 @@
                 
+ 
+   
 log.error(%22Pause
@@ -2483,43 +2483,52 @@
     
-throw new JobInterruptException();%0A
+    Thread.currentThread().interrupt();%0A    
     
@@ -2551,32 +2551,36 @@
 (Throwable t) %7B%0A
+    
                 
@@ -2653,34 +2653,42 @@
 t);%0A            
+   
+ 
 %7D%0A
+    
         %7D while 
@@ -2701,16 +2701,20 @@
 eased);%0A
+    
         
@@ -2757,24 +2757,34 @@
 , jobName);%0A
+        %7D%0A
     %7D%0A%0A    p

move lock release code back into finally block