ScheduledExecutorService works in local & test server but only runs once in live server












4














I have a ScheduledExecutorService to schedule a task to run every 12 hours in a tomcat application. The task calls a REST endpoint and performs some other calculations and returns a result. It works perfectly fine locally and in test server however, it runs only once and never again in the live server. All exceptions are handled and the task takes less than 5 seconds to complete. I have also checked all properties in the server to make sure the time properties are not overridden by other properties. To test locally, I have reduced the delay time to every 10 minutes and this still shows the same behaviour so I’ve ruled time out as the issue. I have looked at other similar questions but none seem to help with this issue.
ScheduledExecutorService only runs once,
JAVA ScheduledExecutorService only runs once when calling a Task<V>,
ScheduledExecutorService only loops once,
ScheduledExecutorService - Task stops running,
ScheduledExecutorService - Ignore already running runnable,
ScheduledExecutorService schedule issue,
Timer vs. ScheduledExecutorService scheduling



Below is my code:



@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder({"name", "number"})
public class Company {

@JsonProperty("name")
private String name;
@JsonProperty("number")
private int number;

public String getName() {
return this.name;
}

public int getNumber() {
return this.number;
}

@Override
public String toString() {
return new ToStringBuilder(Company.class)
.append("name", this.name)
.append("number", this.number).toString();
}
}

public class CompanyDifference {

private String name;
private int difference;

public CompanyDifference(String name, int difference) {
this.name = name;
this.difference = difference;
}

public String getName() {
return this.name;
}

public int getDifference() {
return this.difference;
}

@Override
public String toString() {
return new ToStringBuilder(CompanyDifference.class)
.append("name", this.name)
.append("difference", this.difference).toString();
}
}

@Singleton
public class TaskRunner {
public void doTask () {
try {
System.out.println("takes 2 sets of json data and returns the difference for each company");

// takes 2 sets of json data and returns the difference for each company
ObjectMapper mapper = new ObjectMapper();
InputStream dataOne = Company.class.getResourceAsStream("/data.json");
InputStream dataTwo = Company.class.getResourceAsStream("/data2.json");

Company companyDataOne = mapper.readValue(dataOne, Company.class);
Company companyDataTwo = mapper.readValue(dataTwo, Company.class);

// Find the difference for each company and map company name to difference
Map<String, Integer> mapDifferenceToCompany = new HashMap<>();

for (int i = 0; i < companyDataOne.length; i++) {
mapDifferenceToCompany.put(companyDataOne[i].getName(), Math.abs(companyDataOne[i].getNumber() - companyDataTwo[i].getNumber()));
}

mapDifferenceToCompany.forEach((key, value) -> System.out.println(String.valueOf(new CompanyDifference(key, value))));
} catch (IOException e) {
logger.info(String.format("Error: Failed to convert json to object with exception %s", e));
throw new TaskSchedulerException("Failed to convert json to object with exception", e);
} catch (Exception e) {
logger.info(String.format("Error: Failed with exception %s", e));
throw new TaskSchedulerException("Failed with exception", e);
}
}
}

@Singleton
public class TaskScheduler {

private final Runnable runnable;
private final ScheduledExecutorService executorService;
private static final Logger logger = LoggerFactory.getLogger(TaskScheduler.class);

@Inject
public TaskScheduler(TaskRunner taskRunner, int initialDelay, int period, String timeUnits) {
this.executorService = Executors.newScheduledThreadPool(1);
this.runnable = taskRunner::doTask;

this.scheduledFuture = this.executorService.scheduleAtFixedRate(this.runnable, initialDelay, period,
TimeUnit.valueOf(timeUnits));
}

public static void main(String args) {
TaskRunner taskRunner = new TaskRunner();
new TaskScheduler(taskRunner, 1, 10, "MINUTES");
}
}


The task runs once on start-up after the initial delay of 1 minute but doesn’t run the next scheduled task. It attempts to run the scheduled task but doesn’t seem to complete the task and after examining the ScheduledThreadPoolExecutor properties in the live server, I find that the queue size drops to 0 (when it should always be 1) meaning that no task has been scheduled.



This suggests that when it attempts to run the scheduled task after the initial task is completed, it either removes the scheduled task or it fails to schedule the next task because the current task isn’t completed. No errors or exceptions are thrown as all exceptions have been handled in the doTask method. The scheduler works as expected locally and in the test server which makes it difficult to replicate the scenario.



Want to find out if the implementation is missing something or what might be causing it to not complete the next scheduled task and what makes the queue size drop to 0. Could the java version have any impact on the behaviour of the scheduler or are there any reasons why this might be happening in a live environment?



I created a REST endpoint to monitor what was going on under the hood with the properties from ScheduledFuture and ScheduledThreadPoolExecutor



ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) schedulerService;
this.queueSize = executor.getQueue().size();
this.remainingCapacity = executor.getQueue().remainingCapacity();
this.terminated = schedulerService.isTerminated();
this.shutdown = schedulerService.isShutdown();
this.taskCount = executor.getTaskCount();
this.activeTaskCount = executor.getActiveCount();
this.completedTaskCount = executor.getCompletedTaskCount();
this.keepAliveTime = executor.getKeepAliveTime(TimeUnit.SECONDS);
this.coreThreadTimeOut = executor.allowsCoreThreadTimeOut();
this.cancelled = scheduledFuture.isCancelled();
this.delay = scheduledFuture.getDelay(TimeUnit.MINUTES);


Result of first run after initial delay: from this, we can see that it completed the first task and I do get the required result from the calculations. The taskCount (number of scheduled tasks since start-up) is 2 meaning that the 2nd task has been scheduled and the queue size is still 1 which is fine.



{
"queueSize": 1,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 1,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}


Result after it attempted 2nd run: this is where it gets stuck. The completedTaskCount is 2 but I don’t think it actually completes the task as I don’t get the result from the calculations or any logs to show that it has either started or completed the task. The taskCount should go up to 3 but it is stuck in 2 and the queue size is now 0.



{
"queueSize": 0,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 2,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}


When I check these on the local and test server, it works fine and the taskCount goes up as expected and the queue size is always 1 which is expected. From this, I can tell that for some reason, the task gets stuck on the 2nd run and does not complete so it doesn’t schedule the next task.



The javadoc says: "If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute." I'm assuming this is why the next task is not scheduled. It would be great if you can explain what might cause this to happen










share|improve this question
























  • Can you please provide what actually your "doTask" method does.
    – Amit Bera
    Nov 21 '18 at 17:12










  • @Amit Bera: I have included an example of what the doTask method does.
    – Sam Aig
    Nov 22 '18 at 18:47










  • As far as I can tell you're not closing the streams. Could that be it? A lock on a stream that hangs, thus the second iteration will not run as stream is still opened and locked?
    – Frankie
    Nov 27 '18 at 15:49










  • It still exhibits the same behaviour with the streams closed.
    – Sam Aig
    Nov 27 '18 at 16:45
















4














I have a ScheduledExecutorService to schedule a task to run every 12 hours in a tomcat application. The task calls a REST endpoint and performs some other calculations and returns a result. It works perfectly fine locally and in test server however, it runs only once and never again in the live server. All exceptions are handled and the task takes less than 5 seconds to complete. I have also checked all properties in the server to make sure the time properties are not overridden by other properties. To test locally, I have reduced the delay time to every 10 minutes and this still shows the same behaviour so I’ve ruled time out as the issue. I have looked at other similar questions but none seem to help with this issue.
ScheduledExecutorService only runs once,
JAVA ScheduledExecutorService only runs once when calling a Task<V>,
ScheduledExecutorService only loops once,
ScheduledExecutorService - Task stops running,
ScheduledExecutorService - Ignore already running runnable,
ScheduledExecutorService schedule issue,
Timer vs. ScheduledExecutorService scheduling



Below is my code:



@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder({"name", "number"})
public class Company {

@JsonProperty("name")
private String name;
@JsonProperty("number")
private int number;

public String getName() {
return this.name;
}

public int getNumber() {
return this.number;
}

@Override
public String toString() {
return new ToStringBuilder(Company.class)
.append("name", this.name)
.append("number", this.number).toString();
}
}

public class CompanyDifference {

private String name;
private int difference;

public CompanyDifference(String name, int difference) {
this.name = name;
this.difference = difference;
}

public String getName() {
return this.name;
}

public int getDifference() {
return this.difference;
}

@Override
public String toString() {
return new ToStringBuilder(CompanyDifference.class)
.append("name", this.name)
.append("difference", this.difference).toString();
}
}

@Singleton
public class TaskRunner {
public void doTask () {
try {
System.out.println("takes 2 sets of json data and returns the difference for each company");

// takes 2 sets of json data and returns the difference for each company
ObjectMapper mapper = new ObjectMapper();
InputStream dataOne = Company.class.getResourceAsStream("/data.json");
InputStream dataTwo = Company.class.getResourceAsStream("/data2.json");

Company companyDataOne = mapper.readValue(dataOne, Company.class);
Company companyDataTwo = mapper.readValue(dataTwo, Company.class);

// Find the difference for each company and map company name to difference
Map<String, Integer> mapDifferenceToCompany = new HashMap<>();

for (int i = 0; i < companyDataOne.length; i++) {
mapDifferenceToCompany.put(companyDataOne[i].getName(), Math.abs(companyDataOne[i].getNumber() - companyDataTwo[i].getNumber()));
}

mapDifferenceToCompany.forEach((key, value) -> System.out.println(String.valueOf(new CompanyDifference(key, value))));
} catch (IOException e) {
logger.info(String.format("Error: Failed to convert json to object with exception %s", e));
throw new TaskSchedulerException("Failed to convert json to object with exception", e);
} catch (Exception e) {
logger.info(String.format("Error: Failed with exception %s", e));
throw new TaskSchedulerException("Failed with exception", e);
}
}
}

@Singleton
public class TaskScheduler {

private final Runnable runnable;
private final ScheduledExecutorService executorService;
private static final Logger logger = LoggerFactory.getLogger(TaskScheduler.class);

@Inject
public TaskScheduler(TaskRunner taskRunner, int initialDelay, int period, String timeUnits) {
this.executorService = Executors.newScheduledThreadPool(1);
this.runnable = taskRunner::doTask;

this.scheduledFuture = this.executorService.scheduleAtFixedRate(this.runnable, initialDelay, period,
TimeUnit.valueOf(timeUnits));
}

public static void main(String args) {
TaskRunner taskRunner = new TaskRunner();
new TaskScheduler(taskRunner, 1, 10, "MINUTES");
}
}


The task runs once on start-up after the initial delay of 1 minute but doesn’t run the next scheduled task. It attempts to run the scheduled task but doesn’t seem to complete the task and after examining the ScheduledThreadPoolExecutor properties in the live server, I find that the queue size drops to 0 (when it should always be 1) meaning that no task has been scheduled.



This suggests that when it attempts to run the scheduled task after the initial task is completed, it either removes the scheduled task or it fails to schedule the next task because the current task isn’t completed. No errors or exceptions are thrown as all exceptions have been handled in the doTask method. The scheduler works as expected locally and in the test server which makes it difficult to replicate the scenario.



Want to find out if the implementation is missing something or what might be causing it to not complete the next scheduled task and what makes the queue size drop to 0. Could the java version have any impact on the behaviour of the scheduler or are there any reasons why this might be happening in a live environment?



I created a REST endpoint to monitor what was going on under the hood with the properties from ScheduledFuture and ScheduledThreadPoolExecutor



ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) schedulerService;
this.queueSize = executor.getQueue().size();
this.remainingCapacity = executor.getQueue().remainingCapacity();
this.terminated = schedulerService.isTerminated();
this.shutdown = schedulerService.isShutdown();
this.taskCount = executor.getTaskCount();
this.activeTaskCount = executor.getActiveCount();
this.completedTaskCount = executor.getCompletedTaskCount();
this.keepAliveTime = executor.getKeepAliveTime(TimeUnit.SECONDS);
this.coreThreadTimeOut = executor.allowsCoreThreadTimeOut();
this.cancelled = scheduledFuture.isCancelled();
this.delay = scheduledFuture.getDelay(TimeUnit.MINUTES);


Result of first run after initial delay: from this, we can see that it completed the first task and I do get the required result from the calculations. The taskCount (number of scheduled tasks since start-up) is 2 meaning that the 2nd task has been scheduled and the queue size is still 1 which is fine.



{
"queueSize": 1,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 1,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}


Result after it attempted 2nd run: this is where it gets stuck. The completedTaskCount is 2 but I don’t think it actually completes the task as I don’t get the result from the calculations or any logs to show that it has either started or completed the task. The taskCount should go up to 3 but it is stuck in 2 and the queue size is now 0.



{
"queueSize": 0,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 2,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}


When I check these on the local and test server, it works fine and the taskCount goes up as expected and the queue size is always 1 which is expected. From this, I can tell that for some reason, the task gets stuck on the 2nd run and does not complete so it doesn’t schedule the next task.



The javadoc says: "If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute." I'm assuming this is why the next task is not scheduled. It would be great if you can explain what might cause this to happen










share|improve this question
























  • Can you please provide what actually your "doTask" method does.
    – Amit Bera
    Nov 21 '18 at 17:12










  • @Amit Bera: I have included an example of what the doTask method does.
    – Sam Aig
    Nov 22 '18 at 18:47










  • As far as I can tell you're not closing the streams. Could that be it? A lock on a stream that hangs, thus the second iteration will not run as stream is still opened and locked?
    – Frankie
    Nov 27 '18 at 15:49










  • It still exhibits the same behaviour with the streams closed.
    – Sam Aig
    Nov 27 '18 at 16:45














4












4








4


1





I have a ScheduledExecutorService to schedule a task to run every 12 hours in a tomcat application. The task calls a REST endpoint and performs some other calculations and returns a result. It works perfectly fine locally and in test server however, it runs only once and never again in the live server. All exceptions are handled and the task takes less than 5 seconds to complete. I have also checked all properties in the server to make sure the time properties are not overridden by other properties. To test locally, I have reduced the delay time to every 10 minutes and this still shows the same behaviour so I’ve ruled time out as the issue. I have looked at other similar questions but none seem to help with this issue.
ScheduledExecutorService only runs once,
JAVA ScheduledExecutorService only runs once when calling a Task<V>,
ScheduledExecutorService only loops once,
ScheduledExecutorService - Task stops running,
ScheduledExecutorService - Ignore already running runnable,
ScheduledExecutorService schedule issue,
Timer vs. ScheduledExecutorService scheduling



Below is my code:



@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder({"name", "number"})
public class Company {

@JsonProperty("name")
private String name;
@JsonProperty("number")
private int number;

public String getName() {
return this.name;
}

public int getNumber() {
return this.number;
}

@Override
public String toString() {
return new ToStringBuilder(Company.class)
.append("name", this.name)
.append("number", this.number).toString();
}
}

public class CompanyDifference {

private String name;
private int difference;

public CompanyDifference(String name, int difference) {
this.name = name;
this.difference = difference;
}

public String getName() {
return this.name;
}

public int getDifference() {
return this.difference;
}

@Override
public String toString() {
return new ToStringBuilder(CompanyDifference.class)
.append("name", this.name)
.append("difference", this.difference).toString();
}
}

@Singleton
public class TaskRunner {
public void doTask () {
try {
System.out.println("takes 2 sets of json data and returns the difference for each company");

// takes 2 sets of json data and returns the difference for each company
ObjectMapper mapper = new ObjectMapper();
InputStream dataOne = Company.class.getResourceAsStream("/data.json");
InputStream dataTwo = Company.class.getResourceAsStream("/data2.json");

Company companyDataOne = mapper.readValue(dataOne, Company.class);
Company companyDataTwo = mapper.readValue(dataTwo, Company.class);

// Find the difference for each company and map company name to difference
Map<String, Integer> mapDifferenceToCompany = new HashMap<>();

for (int i = 0; i < companyDataOne.length; i++) {
mapDifferenceToCompany.put(companyDataOne[i].getName(), Math.abs(companyDataOne[i].getNumber() - companyDataTwo[i].getNumber()));
}

mapDifferenceToCompany.forEach((key, value) -> System.out.println(String.valueOf(new CompanyDifference(key, value))));
} catch (IOException e) {
logger.info(String.format("Error: Failed to convert json to object with exception %s", e));
throw new TaskSchedulerException("Failed to convert json to object with exception", e);
} catch (Exception e) {
logger.info(String.format("Error: Failed with exception %s", e));
throw new TaskSchedulerException("Failed with exception", e);
}
}
}

@Singleton
public class TaskScheduler {

private final Runnable runnable;
private final ScheduledExecutorService executorService;
private static final Logger logger = LoggerFactory.getLogger(TaskScheduler.class);

@Inject
public TaskScheduler(TaskRunner taskRunner, int initialDelay, int period, String timeUnits) {
this.executorService = Executors.newScheduledThreadPool(1);
this.runnable = taskRunner::doTask;

this.scheduledFuture = this.executorService.scheduleAtFixedRate(this.runnable, initialDelay, period,
TimeUnit.valueOf(timeUnits));
}

public static void main(String args) {
TaskRunner taskRunner = new TaskRunner();
new TaskScheduler(taskRunner, 1, 10, "MINUTES");
}
}


The task runs once on start-up after the initial delay of 1 minute but doesn’t run the next scheduled task. It attempts to run the scheduled task but doesn’t seem to complete the task and after examining the ScheduledThreadPoolExecutor properties in the live server, I find that the queue size drops to 0 (when it should always be 1) meaning that no task has been scheduled.



This suggests that when it attempts to run the scheduled task after the initial task is completed, it either removes the scheduled task or it fails to schedule the next task because the current task isn’t completed. No errors or exceptions are thrown as all exceptions have been handled in the doTask method. The scheduler works as expected locally and in the test server which makes it difficult to replicate the scenario.



Want to find out if the implementation is missing something or what might be causing it to not complete the next scheduled task and what makes the queue size drop to 0. Could the java version have any impact on the behaviour of the scheduler or are there any reasons why this might be happening in a live environment?



I created a REST endpoint to monitor what was going on under the hood with the properties from ScheduledFuture and ScheduledThreadPoolExecutor



ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) schedulerService;
this.queueSize = executor.getQueue().size();
this.remainingCapacity = executor.getQueue().remainingCapacity();
this.terminated = schedulerService.isTerminated();
this.shutdown = schedulerService.isShutdown();
this.taskCount = executor.getTaskCount();
this.activeTaskCount = executor.getActiveCount();
this.completedTaskCount = executor.getCompletedTaskCount();
this.keepAliveTime = executor.getKeepAliveTime(TimeUnit.SECONDS);
this.coreThreadTimeOut = executor.allowsCoreThreadTimeOut();
this.cancelled = scheduledFuture.isCancelled();
this.delay = scheduledFuture.getDelay(TimeUnit.MINUTES);


Result of first run after initial delay: from this, we can see that it completed the first task and I do get the required result from the calculations. The taskCount (number of scheduled tasks since start-up) is 2 meaning that the 2nd task has been scheduled and the queue size is still 1 which is fine.



{
"queueSize": 1,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 1,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}


Result after it attempted 2nd run: this is where it gets stuck. The completedTaskCount is 2 but I don’t think it actually completes the task as I don’t get the result from the calculations or any logs to show that it has either started or completed the task. The taskCount should go up to 3 but it is stuck in 2 and the queue size is now 0.



{
"queueSize": 0,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 2,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}


When I check these on the local and test server, it works fine and the taskCount goes up as expected and the queue size is always 1 which is expected. From this, I can tell that for some reason, the task gets stuck on the 2nd run and does not complete so it doesn’t schedule the next task.



The javadoc says: "If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute." I'm assuming this is why the next task is not scheduled. It would be great if you can explain what might cause this to happen










share|improve this question















I have a ScheduledExecutorService to schedule a task to run every 12 hours in a tomcat application. The task calls a REST endpoint and performs some other calculations and returns a result. It works perfectly fine locally and in test server however, it runs only once and never again in the live server. All exceptions are handled and the task takes less than 5 seconds to complete. I have also checked all properties in the server to make sure the time properties are not overridden by other properties. To test locally, I have reduced the delay time to every 10 minutes and this still shows the same behaviour so I’ve ruled time out as the issue. I have looked at other similar questions but none seem to help with this issue.
ScheduledExecutorService only runs once,
JAVA ScheduledExecutorService only runs once when calling a Task<V>,
ScheduledExecutorService only loops once,
ScheduledExecutorService - Task stops running,
ScheduledExecutorService - Ignore already running runnable,
ScheduledExecutorService schedule issue,
Timer vs. ScheduledExecutorService scheduling



Below is my code:



@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder({"name", "number"})
public class Company {

@JsonProperty("name")
private String name;
@JsonProperty("number")
private int number;

public String getName() {
return this.name;
}

public int getNumber() {
return this.number;
}

@Override
public String toString() {
return new ToStringBuilder(Company.class)
.append("name", this.name)
.append("number", this.number).toString();
}
}

public class CompanyDifference {

private String name;
private int difference;

public CompanyDifference(String name, int difference) {
this.name = name;
this.difference = difference;
}

public String getName() {
return this.name;
}

public int getDifference() {
return this.difference;
}

@Override
public String toString() {
return new ToStringBuilder(CompanyDifference.class)
.append("name", this.name)
.append("difference", this.difference).toString();
}
}

@Singleton
public class TaskRunner {
public void doTask () {
try {
System.out.println("takes 2 sets of json data and returns the difference for each company");

// takes 2 sets of json data and returns the difference for each company
ObjectMapper mapper = new ObjectMapper();
InputStream dataOne = Company.class.getResourceAsStream("/data.json");
InputStream dataTwo = Company.class.getResourceAsStream("/data2.json");

Company companyDataOne = mapper.readValue(dataOne, Company.class);
Company companyDataTwo = mapper.readValue(dataTwo, Company.class);

// Find the difference for each company and map company name to difference
Map<String, Integer> mapDifferenceToCompany = new HashMap<>();

for (int i = 0; i < companyDataOne.length; i++) {
mapDifferenceToCompany.put(companyDataOne[i].getName(), Math.abs(companyDataOne[i].getNumber() - companyDataTwo[i].getNumber()));
}

mapDifferenceToCompany.forEach((key, value) -> System.out.println(String.valueOf(new CompanyDifference(key, value))));
} catch (IOException e) {
logger.info(String.format("Error: Failed to convert json to object with exception %s", e));
throw new TaskSchedulerException("Failed to convert json to object with exception", e);
} catch (Exception e) {
logger.info(String.format("Error: Failed with exception %s", e));
throw new TaskSchedulerException("Failed with exception", e);
}
}
}

@Singleton
public class TaskScheduler {

private final Runnable runnable;
private final ScheduledExecutorService executorService;
private static final Logger logger = LoggerFactory.getLogger(TaskScheduler.class);

@Inject
public TaskScheduler(TaskRunner taskRunner, int initialDelay, int period, String timeUnits) {
this.executorService = Executors.newScheduledThreadPool(1);
this.runnable = taskRunner::doTask;

this.scheduledFuture = this.executorService.scheduleAtFixedRate(this.runnable, initialDelay, period,
TimeUnit.valueOf(timeUnits));
}

public static void main(String args) {
TaskRunner taskRunner = new TaskRunner();
new TaskScheduler(taskRunner, 1, 10, "MINUTES");
}
}


The task runs once on start-up after the initial delay of 1 minute but doesn’t run the next scheduled task. It attempts to run the scheduled task but doesn’t seem to complete the task and after examining the ScheduledThreadPoolExecutor properties in the live server, I find that the queue size drops to 0 (when it should always be 1) meaning that no task has been scheduled.



This suggests that when it attempts to run the scheduled task after the initial task is completed, it either removes the scheduled task or it fails to schedule the next task because the current task isn’t completed. No errors or exceptions are thrown as all exceptions have been handled in the doTask method. The scheduler works as expected locally and in the test server which makes it difficult to replicate the scenario.



Want to find out if the implementation is missing something or what might be causing it to not complete the next scheduled task and what makes the queue size drop to 0. Could the java version have any impact on the behaviour of the scheduler or are there any reasons why this might be happening in a live environment?



I created a REST endpoint to monitor what was going on under the hood with the properties from ScheduledFuture and ScheduledThreadPoolExecutor



ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) schedulerService;
this.queueSize = executor.getQueue().size();
this.remainingCapacity = executor.getQueue().remainingCapacity();
this.terminated = schedulerService.isTerminated();
this.shutdown = schedulerService.isShutdown();
this.taskCount = executor.getTaskCount();
this.activeTaskCount = executor.getActiveCount();
this.completedTaskCount = executor.getCompletedTaskCount();
this.keepAliveTime = executor.getKeepAliveTime(TimeUnit.SECONDS);
this.coreThreadTimeOut = executor.allowsCoreThreadTimeOut();
this.cancelled = scheduledFuture.isCancelled();
this.delay = scheduledFuture.getDelay(TimeUnit.MINUTES);


Result of first run after initial delay: from this, we can see that it completed the first task and I do get the required result from the calculations. The taskCount (number of scheduled tasks since start-up) is 2 meaning that the 2nd task has been scheduled and the queue size is still 1 which is fine.



{
"queueSize": 1,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 1,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}


Result after it attempted 2nd run: this is where it gets stuck. The completedTaskCount is 2 but I don’t think it actually completes the task as I don’t get the result from the calculations or any logs to show that it has either started or completed the task. The taskCount should go up to 3 but it is stuck in 2 and the queue size is now 0.



{
"queueSize": 0,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 2,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}


When I check these on the local and test server, it works fine and the taskCount goes up as expected and the queue size is always 1 which is expected. From this, I can tell that for some reason, the task gets stuck on the 2nd run and does not complete so it doesn’t schedule the next task.



The javadoc says: "If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute." I'm assuming this is why the next task is not scheduled. It would be great if you can explain what might cause this to happen







java scheduling runnable executorservice scheduledexecutorservice






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 27 '18 at 15:15







Sam Aig

















asked Nov 21 '18 at 16:49









Sam AigSam Aig

265




265












  • Can you please provide what actually your "doTask" method does.
    – Amit Bera
    Nov 21 '18 at 17:12










  • @Amit Bera: I have included an example of what the doTask method does.
    – Sam Aig
    Nov 22 '18 at 18:47










  • As far as I can tell you're not closing the streams. Could that be it? A lock on a stream that hangs, thus the second iteration will not run as stream is still opened and locked?
    – Frankie
    Nov 27 '18 at 15:49










  • It still exhibits the same behaviour with the streams closed.
    – Sam Aig
    Nov 27 '18 at 16:45


















  • Can you please provide what actually your "doTask" method does.
    – Amit Bera
    Nov 21 '18 at 17:12










  • @Amit Bera: I have included an example of what the doTask method does.
    – Sam Aig
    Nov 22 '18 at 18:47










  • As far as I can tell you're not closing the streams. Could that be it? A lock on a stream that hangs, thus the second iteration will not run as stream is still opened and locked?
    – Frankie
    Nov 27 '18 at 15:49










  • It still exhibits the same behaviour with the streams closed.
    – Sam Aig
    Nov 27 '18 at 16:45
















Can you please provide what actually your "doTask" method does.
– Amit Bera
Nov 21 '18 at 17:12




Can you please provide what actually your "doTask" method does.
– Amit Bera
Nov 21 '18 at 17:12












@Amit Bera: I have included an example of what the doTask method does.
– Sam Aig
Nov 22 '18 at 18:47




@Amit Bera: I have included an example of what the doTask method does.
– Sam Aig
Nov 22 '18 at 18:47












As far as I can tell you're not closing the streams. Could that be it? A lock on a stream that hangs, thus the second iteration will not run as stream is still opened and locked?
– Frankie
Nov 27 '18 at 15:49




As far as I can tell you're not closing the streams. Could that be it? A lock on a stream that hangs, thus the second iteration will not run as stream is still opened and locked?
– Frankie
Nov 27 '18 at 15:49












It still exhibits the same behaviour with the streams closed.
– Sam Aig
Nov 27 '18 at 16:45




It still exhibits the same behaviour with the streams closed.
– Sam Aig
Nov 27 '18 at 16:45












1 Answer
1






active

oldest

votes


















0














Issue was not with the implementation, the implementation is fine. After much debugging, the VM box running the app seemed to have had a glitch. After restarting multiple times and redeploying app service, It's back to normal.
Please see question for steps taken when debugging app.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53416915%2fscheduledexecutorservice-works-in-local-test-server-but-only-runs-once-in-live%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    Issue was not with the implementation, the implementation is fine. After much debugging, the VM box running the app seemed to have had a glitch. After restarting multiple times and redeploying app service, It's back to normal.
    Please see question for steps taken when debugging app.






    share|improve this answer


























      0














      Issue was not with the implementation, the implementation is fine. After much debugging, the VM box running the app seemed to have had a glitch. After restarting multiple times and redeploying app service, It's back to normal.
      Please see question for steps taken when debugging app.






      share|improve this answer
























        0












        0








        0






        Issue was not with the implementation, the implementation is fine. After much debugging, the VM box running the app seemed to have had a glitch. After restarting multiple times and redeploying app service, It's back to normal.
        Please see question for steps taken when debugging app.






        share|improve this answer












        Issue was not with the implementation, the implementation is fine. After much debugging, the VM box running the app seemed to have had a glitch. After restarting multiple times and redeploying app service, It's back to normal.
        Please see question for steps taken when debugging app.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Dec 6 '18 at 0:49









        Sam AigSam Aig

        265




        265






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53416915%2fscheduledexecutorservice-works-in-local-test-server-but-only-runs-once-in-live%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Wiesbaden

            Marschland

            Dieringhausen