matrei commented on issue #16801:
URL: https://github.com/apache/grails-core/issues/16801#issuecomment-6572480997
Thanks for the reproducer. I can reproduce this on 9.0.x with a real
`HibernateDatastore` in DATABASE mode, and 8.0.0 has the same code.
To your question: no, `@CurrentTenant` together with `@Transactional` is not
bad practice. This is a bug, actually two:
1. The `getTransactionManager()` that `@Transactional` generates (and the
one `ServiceTransformation` generates for data services) looks up the tenant
with the unscoped `CurrentTenantHolder.get()`. That throws as soon as the
thread holds different tenants for different datastores. It should ask for the
tenant of the datastore it picks the transaction manager from.
2. The reason two different tenants are bound in the first place: for a
class that is not a `@Service`, `@CurrentTenant` gets its `TenantService` from
`findSingleDatastore()`. In DATABASE mode, inside `Tenants.withId('test')`,
that returns the child datastore of `test`, not the primary one. Nothing is
bound for the child, so it asks the tenant resolver. Yours returns `default`
outside a web request, and that gets bound to the child. Now the thread has
`test` for the primary datastore and `default` for the child. `@Service`
classes already avoid this by using `findServiceDatastore()`.
Fixing only 1 is what your workaround does. The exception goes away and the
save goes to the right database, but inside the method `Tenants.currentId()`
still returns `default` instead of `test`. `TenantPropertyService.setValue`
uses that as the key into `inMemoryProperties`, so with the workaround the
cached value probably ends up under the wrong tenant.
Minimal reproducer:
```groovy
@CurrentTenant
@Transactional
class CtxWidgetService {
void save(String name) {
new CtxWidget(name: name).save(flush: true, failOnError: true)
}
}
// DATABASE mode, a `test` datasource and a tenant resolver that returns
'default'
Tenants.withId('test') {
service.save('widget')
}
// TenantException: Cannot resolve a single current tenant: [default, test]
are bound on this thread for different datastores. ...
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]