Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在spring中扩展多个实例并处理计划任务?_Java_Spring_Postgresql_Spring Boot_Scheduled Tasks - Fatal编程技术网

Java 如何在spring中扩展多个实例并处理计划任务?

Java 如何在spring中扩展多个实例并处理计划任务?,java,spring,postgresql,spring-boot,scheduled-tasks,Java,Spring,Postgresql,Spring Boot,Scheduled Tasks,我每天早上8点在欧洲/巴黎通过spring boot向android和ios应用程序发送推送通知 如果我运行多个实例,通知将发送多次。我想每天发送通知,发送到数据库,并检查它们,但我担心它仍会运行多次,这就是我正在做的: @组件 公共类ScheduledTasks{ 私有静态最终记录器log=LoggerFactory.getLogger(ScheduledTasks.class); 私有静态最终SimpleDataFormat dateFormat=新SimpleDataFormat(“HH:

我每天早上8点在欧洲/巴黎通过spring boot向android和ios应用程序发送推送通知

如果我运行多个实例,通知将发送多次。我想每天发送通知,发送到数据库,并检查它们,但我担心它仍会运行多次,这就是我正在做的:

@组件
公共类ScheduledTasks{
私有静态最终记录器log=LoggerFactory.getLogger(ScheduledTasks.class);
私有静态最终SimpleDataFormat dateFormat=新SimpleDataFormat(“HH:mm:ss”);
@自动连线
专用ExpoPushTokenRepository ExpoPushTokenRepository;
@自动连线
私人ExpoPushNotificationService ExpoPushNotificationService;
@自动连线
私有消息源;
//TODO:如果实例>1,这将运行多次,将发送的通知保存到数据库并防止多次发送。
@已计划(cron=“${cron.promotions.notification}”,zone=“欧洲/巴黎”)
公共无效sendNewPromotionsNotification(){
List expoPushTokenList=expoPushTokenRepository.findAll();
ArrayList notifyRequestList=新建ArrayList();
用于(ExpoPushToken ExpoPushToken:expoPushTokenList){
NotifyRequest NotifyRequest=新NotifyRequest(
expoPushToken.getToken(),
“这是一个测试标题”,
“这是一个测试字幕”,
“这是一个测试机构”
);
notifyRequestList.add(notifyRequest);
}
expoPushNotificationService.sendPushNotificationToList(notifyRequestList);
log.info(“{}将推送通知发送到”+expoPushTokenList.size()+“userse”,dateFormat.format(new Date());
}
}
有人知道我如何安全地防止这种情况发生吗?

对于手头的任务来说,这将是我主要的数据库无关解决方案,但被排除在外,因此我们不打算讨论它

我们将要探讨的解决方案是以下假设:

  • 使用Postgres
    =9.5
    (因为我们将使用)
  • 可以运行本机查询
在这种情况下,我们可以通过以下查询从运行的应用程序的多个实例中检索批通知:

SELECT * FROM expo_push_token FOR UPDATE SKIP LOCKED LIMIT 100;
这将从表
expose\u push\u token
中检索并锁定多达
100个
条目。如果应用程序的两个实例同时执行此查询,则收到的结果将是不相交的
100
只是一些示例值。您可能需要针对您的用例微调此值。在当前事务结束之前,锁一直处于活动状态

在实例获取一批通知后,它还必须从表中删除它锁定的条目,或以其他方式标记该条目已被处理(如果我们沿着这条路线走,我们必须修改上面的查询以过滤掉已处理的entires)并关闭当前事务以释放锁。然后,应用程序的每个实例将重复此查询,直到查询返回零个条目

还有一种替代方法:实例首先获取要发送的通知的批量大小,将事务保持在数据库打开状态(从而继续保持数据库的锁定),发送其通知,然后删除/更新条目并关闭事务

这两种解决方案具有不同的优势/劣势:

  • 第一种解决方案使事务保持简短。但是,如果应用程序在发送通知的过程中崩溃,则其未发送的批处理部分在本次运行中丢失。
  • 第二种解决方案使事务保持打开状态,可能会持续很长时间。如果在发送通知的中间崩溃,所有条目都将被解锁,其批将被重新处理,可能导致一些通知被发送出去两次。


为了使这个解决方案起作用,我们还需要某种工作,用我们需要的数据填充表
expo\u push\u token
。此作业应提前运行,即其执行不应与通知发送过程重叠。

您可以使用此操作。如果使用quartz和约束导致我们选择简单、快速和肮脏,我们已经探讨了此想法。你有没有一个可以用这种方法来完成的想法?你使用的是什么版本的postgres?并且被选中的个人ID是否在其自己的表中接收通知?或者可以把它们放在一张单独的桌子上?您愿意执行本机查询吗?回答得很好,感谢您教授pgsql的这一部分。我会选择第一个解决方案,但我仍然想知道,由于推送是通过外部API完成的,我们必须首先拥有来自
expo\u push\u token
的条目,然后我们将能够查询外部API,这可能会解锁条目,除非我
在同一查询中删除它们,这样它们就不能被重用。第一个解决方案可以改进吗?如果我理解正确的话,还有一个额外的步骤:1。锁具,2。从外部API获取数据,3。删除条目,关闭事务4。发送通知。是这样吗?我相信应该这样做。验证通知_历史记录中的今天行不存在2。将今日通知添加到通知历史记录3中。联系4。发送通知。你不这么认为吗?我们可以继续讨论吗?我今天要坐飞机。我想稍后再聊。我怎么联系你?对我提议的实施有什么想法吗?