Java ScheduledExecutorService在本地和;测试服务器,但仅在live server中运行一次
我有一个ScheduledExecutorService,用于在tomcat应用程序中计划每12小时运行一次任务。该任务调用REST端点并执行一些其他计算并返回结果。它在本地和测试服务器中工作得非常好,但是,它只在实时服务器中运行一次,而且永远不会再次运行。所有异常都已处理,任务完成所需时间不到5秒。我还检查了服务器中的所有属性,以确保时间属性不会被其他属性覆盖。为了进行本地测试,我将延迟时间减少到每10分钟一次,这仍然显示出相同的行为,因此我排除了时间问题。我看过其他类似的问题,但似乎没有一个能解决这个问题。 , , , , , , 下面是我的代码:Java ScheduledExecutorService在本地和;测试服务器,但仅在live server中运行一次,java,scheduling,runnable,executorservice,scheduledexecutorservice,Java,Scheduling,Runnable,Executorservice,Scheduledexecutorservice,我有一个ScheduledExecutorService,用于在tomcat应用程序中计划每12小时运行一次任务。该任务调用REST端点并执行一些其他计算并返回结果。它在本地和测试服务器中工作得非常好,但是,它只在实时服务器中运行一次,而且永远不会再次运行。所有异常都已处理,任务完成所需时间不到5秒。我还检查了服务器中的所有属性,以确保时间属性不会被其他属性覆盖。为了进行本地测试,我将延迟时间减少到每10分钟一次,这仍然显示出相同的行为,因此我排除了时间问题。我看过其他类似的问题,但似乎没有一个
@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");
}
}
初始延迟后第一次运行的结果:从中,我们可以看到它完成了第一个任务,并且我确实从计算中得到了所需的结果。taskCount(自启动以来已调度的任务数)为2,表示第二个任务已调度,队列大小仍然为1,这很好
{
"queueSize": 1,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 1,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}
尝试第二次运行后的结果:这是它卡住的地方。completedTaskCount是2,但我不认为它实际上完成了任务,因为我没有从计算或任何日志中获得结果,以表明它已经开始或完成了任务。taskCount应该增加到3,但它被固定在2,队列大小现在为0
{
"queueSize": 0,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 2,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}
当我在本地和测试服务器上检查这些时,它工作正常,任务计数按预期增加,队列大小始终为1,这是预期的。从这一点上,我可以看出,由于某种原因,任务在第二次运行时被卡住,无法完成,因此它无法安排下一个任务
javadoc说:“如果此任务的任何执行时间超过其周期,则后续执行可能会延迟开始,但不会同时执行。”我假设这就是下一个任务没有计划的原因。如果您能解释可能导致这种情况发生的原因,那就太好了。问题不在实现中,实现很好。经过多次调试,运行该应用程序的虚拟机盒似乎出现了故障。在多次重新启动并重新部署应用程序服务后,它将恢复正常。
有关调试应用程序时所采取的步骤,请参见问题。您能否提供“doTask”方法的实际功能。@阿米特·贝拉:我已经提供了一个doTask方法的功能示例。据我所知,您没有关闭流。是吗?挂起的流上的锁,因此第二次迭代将不会运行,因为流仍处于打开和锁定状态?它在流关闭时仍表现出相同的行为。
{
"queueSize": 0,
"remainingCapacity": 2147483647,
"terminated": false,
"shutdown": false,
"taskCount": 2,
"activeTaskCount": 0,
"completedTaskCount": 2,
"keepAliveTime": 0,
"coreThreadTimeOut": false,
"periodic": true,
"cancelled": false
}