class Document{
hasMany{ changes: PendingChange}
}
class DocumentService{
def acceptAll(){
def owner = Document.get(params.id)
def changes = owner.changes.findAll{it.status == "pending"}.collect{it.id}
executorWrapperService.processClosure({
changes.each{pc -> //*1
changeService.accept(pc)
}
}, owner)
redirect(url: request.getHeader('referer'))
}
}
class DocumentController{
def index(){
def result = [:]
def owner = Document.get(params.id)
//even if processing running, we want to show how many are left. Accept/Reject buttons will be disabled if processingpc is true
result.changes = owner.changes.findAll{it.status == "pending"}
if(executorWrapperService.hasRunningProcess(owner)){ //*2
result.processingpc = true
}
.
.
.
return result
}
}
class ExecutorWrapperService {
def executorService
ConcurrentHashMap<Object,java.util.concurrent.FutureTask> activeFuture = [:]
def processClosure(clos,owner){
owner = "${owner.class.name}:${owner.id}"
//see if we got a process running for owner already
def existingFuture = activeFuture.get(owner)
if(!existingFuture){
//start new thread and store the process
def future = executorService.submit(clos as java.util.concurrent.Callable)
activeFuture.put(owner,future)
}else{
//if a previous process for this owner is done, remove it and start new one
if(existingFuture.isDone()){
activeFuture.remove(owner)
processClosure(clos,owner)
}
//if not done, do something else
}
}
def hasRunningProcess(owner){
owner = "${owner.class.name}:${owner.id}"
// There is no process running for this owner
if(activeFuture.get(owner) == null){
return false
// there was a process, but now its done.
}else if(activeFuture.get(owner).isDone()){
activeFuture.remove(owner)
return false
// we have a running process
}else if(activeFuture.get(owner).isDone() == false){
return true
}
}
}
上面的代码演示了正在发生的事情。在我的索引屏幕上,我显示了一个更改列表。当用户点击accept all
按钮时,系统会调用DocumentService.acceptAll
。然后创建一个新线程并开始应用更改。这对数据库对象有影响。该请求被重定向到index
。因为我想在处理过程中禁用对挂起更改的任何操作,ExecutorWrapperService.activeFuture
用于告诉DocumentController是否存在该文档的处理。执行DocumentController.index
时,我只读取数据库字段以供显示,不会发生任何写入。
执行上述操作时,偶尔会出现以下错误之一:
events.PatchedDefaultFlushEventListener - Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Document#1495]
在线* 1,或在线* 2上的相同错误。 我相信这与我正在创建的线程有关。 我试图想象我应该如何使用事务或会话来解决这个问题,但还没有做到。