Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes several documentation issues #9

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/docs/guide/2. Multi-Tenant Modes.gdoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ tenant {
}
{code}

{warn}multiTenant is the default{warn}
{warning}multiTenant is the default{warning}
25 changes: 17 additions & 8 deletions src/docs/guide/2.1 Multi-Tenant Database Set Up.gdoc
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
h2. Annotate Domain Classes
The 'multiTenant' mode relies your application to use just one database for all tenants running. This is useful when you have a SaaS that allows user to sign up online and have their tenants running just after signing up. This is the simpler approach on multi-tenancy.

As of 0.10, you only have to annotate domain classes that you want to be multi-tenant. Any domain classes that you want to be shared, such as acegi Role/Requestmap can be left without the annotation.
First tell the plugin which classes will be treated as multi-tenant ones. You can do it by annotating your domain classes with the *@MultiTenant* annotation, as show below:

{code}
import grails.plugin.multitenant.core.groovy.compiler.MultiTenant;
import grails.plugin.multitenant.core.groovy.compiler.MultiTenant

@MultiTenant class MyDomainClass {
@MultiTenant
class MyDomainClass {

}
{code}

Because the plugin hooks into the compiler, make sure to do a "grails clean" after you've annotated your classes. Eventually, we'd like to get rid of this step.
This way, each instance of MyDomainClass will belong to some tenant. To achieve this, the plugin hooks into all hibernate events that query your database, adding another condition in your queries that will filter just instances of the current tenant.

h2. A note on indexing in multi-tenant environment
For example, imagine you have 2 tenants, each one with 2 instances of MyDomainClass. When the app is running on tenant 1, calling

Indexing a multi-tenant database is a tricky beast. If you have large datasets (100MM-1BB), prepare yourself for some fun. Google multi-tenant databases and start reading. :)
{code}
def lst = MyDomainClass.list()
{code}

will return just its 2 instances, even if you have 4 in your database.

The plugin hooks either on save/update events, setting the value of tenantId property automagically.

The short of it is that it's probably most efficient to create multi-column indexes that always include tenantId, that way the db can limit the working set to a single tenant before it starts filtering on another field.
{warning}
You do not need to declare the 'tenantId' property, the plugin even auto-injects it for you, to keep your domain class code clean
{warning}
5 changes: 5 additions & 0 deletions src/docs/guide/2.1.1 Multi-Tenant mode gotchas.gdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
h3. A note on indexing in multi-tenant environment

Indexing a multi-tenant database is a tricky beast. If you have large datasets (100MM-1BB), prepare yourself for some fun. Google 'multi-tenant databases' and start reading. :)

The short of it is that it's probably most efficient to create multi-column indexes that always include tenantId, that way the db can limit the working set to a single tenant before it starts filtering on another field.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
The single-tenant option is a little more immature than the multi-tenant option. It inherits all datasource configuration from the default datasource in Datasource.groovy, and allows you to provide a custom datasource url per tenant. This means that you can't mix and match drivers or user/pass combos for different tenants in the same instance.

{warn}
{warning}
TenantUtils.doWithTenant and currentTenant.set() do not work in single tenant mode, unless you manually create a new hibernate session and bind it to the current thread.

Also, normal second-level caches will not work in single-tenant mode, as you will get primary key collisions across databases. You'll need to use a multi-tenant wrapper for your cache implementation (see below)
{warn}
{warning}

The plugin supports the following types of datasources:

Expand Down Expand Up @@ -92,4 +92,4 @@ If you use the OpenSymphony cache provider (org.hibernate.cache.OSCacheProvider)

h3. EHCache(New with 0.18)

If you are using the EHCache cache provider your should use *grails.plugin.multitenant.ehcache.cache.MultiTenantEhCacheProvider* insead.
If you are using the EHCache cache provider your should use *grails.plugin.multitenant.ehcache.cache.MultiTenantEhCacheProvider* instead.
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ grails create-dns-map

h2. Security and TenantId

{warn}
{warning}
One advantage of identifying tenants by domain name is that any session cookies will be unique per domain, helping with security. This means that if a user authenticates (and gets an authentication cookie), if he changes the domain he's using to access the application, he won't stay logged on because the cookie for the old domain won't apply.

This does have a loophole, though. Because the cookie lives on the client browser, it may be possible for the user to inspect the cookie, and copy any values such as jsessionid to a cookie for a different domain, thus gaining access to another tenant's data. It really depends on how secure your cookie is (does an authentication token only work for one domain?)

The multi-tenant plugin uses a very simple messaging system from the falcone-util plugin. Whenever the tenantId changes, a message is published with the new and old tenantIds. You can use this event to perform any necessary checks, and clean up any resources you don't want around when the tenantId changes. Example as follows:
{warn}
{warning}

{code}
//A sample class that might contain an authenticated user
Expand Down