【发布时间】:2021-10-31 22:56:18
【问题描述】:
使用 Grails 4.0.10 我编写了一个基于鉴别器的多租户应用程序的大部分工作。现在的问题是实施“看门人”。这是一项计划服务,它会扫描数据库中超过截止日期的文档,并为它们分配“过期”状态。
Document 是一个多租户域。看门人应该跨租户工作。
计划的服务产生一个异步操作。使用 Tenants.withoutId 查找所有候选文档按预期工作。
更新数据库时出现问题。即使逻辑包含在Tenants.withId 中,操作也会以TenantNotFoundException 结束。没有找到租户,事务被回滚。
这发生在提交事务时。多个save() 操作和审计日志此时已顺利完成。
了解来源:Document 域与其他域相关联:Assignment(普通)、AsmProgress(多租户)、DocAction(多租户)。对于给定的文档,所有这些都属于同一个租户。 logRecordService 是一个审计服务。
这里是关键的源代码。
def forceExpireMultiple(InsUser actor, Map docActions) {
if (log.debugEnabled) log.debug "FORCE_EXPIRE_MULTIPLE_S << ${actor}, ${docActions?.keySet()}"
docActions.each {entry ->
String caseId = entry.key
DocAction docAction = entry.value
// Each doc action is expired in its own transaction.
DocAction.withTransaction {status ->
if (log.traceEnabled) log.trace "forceExpireMultiple.ttag: ${docAction.ttag}"
Tenants.withId(docAction.ttag) {
docAction = get(docAction.id)
doForceExpire(actor, caseId, docAction)
}
}
}
}
/**
* Expire a single doc action with its assignments and document.
*/
private doForceExpire(InsUser actor, String caseId, DocAction docAction) {
if (log.debugEnabled) log.debug "DO_FORCE_EXPIRE_S << ${caseId}, ${docAction}"
final String ttag = docAction.ttag
// Terminate all assignments.
docAction.assignments.each {assignment ->
def progress = AsmProgress.of(assignment, ProgressType.EXPIRED)
progress.ttag = ttag
progress.save(failOnError: true)
// The assignment is now done.
assignment.stage = AsmState.FINISHED
assignment.save(failOnError: true)
logRecordService.logExpire(assignment, actor)
}
// Expire document.
Document document = docAction.document
document.expire()
document.save(failOnError: true)
logRecordService.logExpire(document, actor)
// Expire the doc action itself.
docAction.expire()
docAction.save(failOnError: true)
logRecordService.logExpire(docAction, actor)
}
这里是一些调试和堆栈跟踪输出,为便于阅读而编辑。
[pool-1-thread-1] se.insignia.web.DocActionService: FORCE_EXPIRE_MULTIPLE_S << [User global::policy], [FDH176]
[pool-1-thread-1] se.insignia.web.DocActionService: forceExpireMultiple.ttag: acme
[pool-1-thread-1] se.insignia.web.DocActionService: DO_FORCE_EXPIRE_S << FDH176, FDH176/acme(ACTIVE): ... (Acme Industries Ltd.)
[pool-1-thread-2] se.insignia.web.log.LogRecordService: Logging Assignment with tenantId [acme]
[pool-1-thread-3] se.insignia.web.log.LogRecordService: Logging Document with tenantId [acme]
[pool-1-thread-4] se.insignia.web.log.LogRecordService: Logging DocAction with tenantId [acme]
org.grails.datastore.mapping.multitenancy.exceptions.TenantNotFoundException: Tenant could not be resolved outside a web request
at grails.gorm.multitenancy.Tenants.currentId(Tenants.groovy:73)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:100)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:453)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
at se.insignia.web.DocAction.withTransaction(DocAction.groovy)
at se.insignia.web.DocActionService$_forceExpireMultiple_closure6.doCall(DocActionService.groovy:262)
[This is withTransaction in forceExpireMultiple]
at se.insignia.web.DocActionService.forceExpireMultiple(DocActionService.groovy:258)
从调试输出中,您可以看到所有doForceExpire 都在异常之前执行,包括审计日志记录。
根本原因是什么,我怎样才能找到它?显然,我自己的代码之外的一些假设被违反了。它们是什么?
我尝试了许多代码变体,包括注释掉所有审计日志。
【问题讨论】:
-
您使用的是哪个租户解析器?看起来您可能正在使用需要主动请求的请求。
-
对,一个子域租户解析器,仿照 doco 中的那个。是的,它的正常模式是对 Web 请求进行操作。但也有需要访问其他租户的监督角色。到目前为止,“Tenants.withId”已经完成了这项工作。
标签: hibernate grails grails-orm