The cache branch of this repository contains logic showing how to use Grails Cache Plugin with the tenant Id as part of the cache key.
The sample code
- Overrides bean
customCacheKeyGenerator
. It adds the tenantId as part of the key. - Creates several cache related classes based on the plugin default
CustomCacheKeyGenerator
- Adds a EvictController and service. They show how to evict cache for a particular tenant.
- Adds @Cacheable to the BookListService.
When the cache is not hit you will see a log line:
INFO --- [nio-8080-exec-2] example.BookListService : not cached
The index page of the application http://localhost:8080 contains links to evict the cache.
This Grails application uses GORM for Hibernate.
It uses DISCRIMINATOR
multi-tenancy mode by setting at grails-app/conf/application.yml
the following:
grails:
gorm:
multiTenancy:
mode: DISCRIMINATOR
It has a domain class Book
which uses a custom field tenant
as the tenancy discriminator.
package example
import grails.compiler.GrailsCompileStatic
import grails.gorm.MultiTenant
@GrailsCompileStatic
class Book implements MultiTenant<Book> {
...
String tenant
static constraints = {
...
static mapping = {
tenantId name:'tenant'
}
}
In grails-app/init/BootStrap.groovy
multiple Books are saved. To select the tenant, for which the books are being saved, the method MultiTenant::withTenant(Serializable, Closure)
is used.
- For tenant
groovy
, the application saves 5 books - For tenant
grails
, the application saves 8 books - For tenant
micronaut
, the application saves 1 books
To save the books, Boostrap
injects BookService
a GORM Data Service annotaed with @CurrentTenant
, an annotation which resolves the current tenant for the context of a class or method. It uses the method BookService::save(String, String, String, String, String)
The application exposes following endpoints:
- GET
/books/groovy
returns books of current tenantgroovy
- GET
/books/grails
returns books of current tenantgrails
- GET
/books/micronaut
returns books of current tenantmicronaut
- GET
/books/groovygrails
returns books of current tenantgroovy
and books of an extra tenantgrails
To allow queries which fetch current tenant items plus items belonging to other tenant BookService
extends an abstract
class DataService
@CompileStatic
@CurrentTenant
@Service(Book)
abstract class BookService extends DataService<Book> {
@Autowired
HibernateDatastore hibernateDatastore
@Override
HibernateDatastore getHibernateDataStore() {
return this.hibernateDatastore
}
@Override
DetachedCriteria<Book> getDetachedCriteria() {
Book.where {}
}
...
To allow fetching information coming from multiple tenants DataService<T>
exposes a method:
DetachedCriteria<T> criteriaInTenants(String... additionalTenant = null)
DetachedCriteria
allows for dynamic constructions of queries. If you build the criteria with criteriaInTenant
execute the query within the Closure
of Tenants.withoutId(Closure)
. Example:
...
Number count(String additionalTenant = null) {
DetachedCriteria<Book> c = criteriaInTenants(additionalTenant)
Tenants.withoutId {
c.count()
}
}
...