在本地应用程序引擎dev-server上使用对象化事务和GAE任务时,我遇到了一个问题。
我想做的是以并行方式处理一个巨大的csv文件(将数据解析并写入其他地方)。为此,第一个servlet负责:
每个任务都要处理其较小的csv块对象。
现在,出现问题。为了确定何时正确处理了所有块,我希望最后一个产生另一个任务,以完成一些工作。
这样做的目的是使用事务,以确保每个完成的块处理都增加Job实例上的计数器,以便最后一个实例可以启动最终任务。
但是,这不起作用。我已经尝试过将Job分成7个块,似乎最后两个块是同时处理的(很好!),但是它们两个都成功(使用不同的时间)。可以想象,这两个任务在处理的块数为5时开始执行,并且都尝试将6设置为处理的块。我期望发生的是,退出事务时,其中之一失败,并且只有一个应该能够更新父对象上的处理后的块值。因此,下次重试时,块计数从6开始,而不是从5开始。
因此,为方便起见,这是执行的代码。
items = []
categories = Category.objects.all()
for category in categories:
items.extend(list(Item.objects.filter(category=category)[:10]))
以下是输出(仅具有Thread指示的相关部分):
// import static com.googlecode.objectify.ObjectifyService.ofy;
// ...
// ...
// Perform the data manipulation on the Chunk
// ...
// Load the parent job from Datastore
// job = ...
// Check if there still are valid chunks to process. If not, we are done!
ImportJob fctUpdatedJob = ofy().transact(() -> {
long threadId = Thread.currentThread().getId();
log.info("T{}: Transaction started", threadId);
ImportJob updatedJob = ofy().load().key(Key.create(ImportJob.class, job.getId())).now();
log.info("T{}: loaded job {}", threadId, updatedJob);
int processedChunks = updatedJob.getProcessedChunks() + 1;
updatedJob.setProcessedChunks(processedChunks);
updatedJob.setTotalChunkSeconds(updatedJob.getTotalChunkSeconds() + seconds);
// TODO Double check this stop condition
if (processedChunks == updatedJob.getTotalChunks() && !updatedJob.isDisposing()) {
updatedJob.setDisposing(true);
}
ofy().save().entity(updatedJob).now();
log.info("T{}: job saved. Job: {}", threadId, updatedJob);
return updatedJob;
});
if (job.getProcessedChunks()==job.getTotalChunks()) {
// We are done!
// Launch the final task
}
如您所见,T22以5个已处理的块开头,将其保存为6,然后T20从5再次开始,并将其保存为6。因此,处理条件unks == totalChunks永远不会发生。
我正在本地AppEngine开发服务器上使用objectify版本5.1.6,并且在我的appengine-web.xml中启用了该选项。
我在这里想念什么?