我有以下服务,基本上按照特定时间间隔安排,以执行以下操作:
这些下载可能需要1-2个小时。根据您在班级布局中的内容以及我所理解的内容,我将在整个预定服务期间永久处于交易中。
@Stateless
public class TimedService {
@EJB
private Facade facade;
@Schedule(hour="*/12")
public void run() {
List<String> urls = getAllUrls();
urls.forEach(u -> {
facade.downloadFromUrl(u);
});
}
}
@Stateless
public class Facade {
@EJB
private Dao dao;
public void downloadFromUrl(String url) {
//this is the download part that may take a couple of minutes
byte[] bytes = NetUtils.getByteArrayFromUrl(url);
//if download was succesfull
if(bytes != null) {
//save the filename to disk
String fileName = createFileName(url);
Files.write(fileName, bytes);
//save entity to the database with the fileName location
Entity e = new Entity(fileName);
dao.merge(e);
}
}
}
所以基本上要么Wildfly超时了(默认是5分钟),要么我把它改成24小时内就像超时那么大。
如果我理解正确,即使Facade#downloadFromUrl
交易中的超时可能没有被触发,因为单个下载没有持续那么长时间,我仍然在TimedService#run
交易中打开完成所有下载所需的整个持续时间。
那么有没有更好的方法而不仅仅是将事务超时调整到一个庞大的数字?
答案 0 :(得分:2)
如果服务器提供了下载,则应考虑使用ExecutorService或容器管理线程池对下载进行多线程处理。这将提高整体吞吐量。另外一般来说,最好将事务置于服务级别以保证操作是原子操作,但在这种情况下,它是后台任务,因此在将数据写入db时可以放置事务。如果下载集需要是原子的,您可以加入所有下载的执行程序提交结果,以创建所有数据库写入在所有下载完成后发生的屏障。
答案 1 :(得分:1)
一种方法可能是使用 JMS 。如果您对每个下载1个事务而不是整个过程中的单个事务感到满意,则可以run()
向每个URL发送消息到消息驱动Bean 以下载MDB做facade.downloadFromUrl(u);