Skip to content
This repository was archived by the owner on Mar 10, 2025. It is now read-only.
This repository was archived by the owner on Mar 10, 2025. It is now read-only.

Multi-Tenant startup - TenantNotFoundException (gorm-graphql 1.0.3-BUILD-SNAPSHOT/Grails 4.0.0) #24

@ianibo

Description

@ianibo

Hi

Currently looking to see if this plugin might be able to help in a multi-tenant (database schema-per-tenant) microservice component that we would like to transition to graphql.

I'm having a problem using the plugin in our component because the example tenant app uses the SystemPropertyTenantResolver - which means that the example project has a tenant ID in it's hand at application startup time. This in turn means that when the doWithSpring block in GormGraphqlGrailsPlugin.groovy executes the ultimate call to findStaticApi in GormEnhancer can work as in a single tenant environment.

However, in a real multi-tenant scenario (We're using schema-per-tenant, which I suspect might give us a different problem) systems will usually derive the tenant from some property of the request - and as such, the tenant identifier is not available at spring-controlled component init time. The plugin currently fails with the stack-trace at the bottom of this issue when started with a non-test tenant resolver.

I'd like to help resolve this, but could use some advice on the best way forward - I was wondering about a defer option which would delay the call to Schema.generate until the first request came along? Appreciate thats not great for pre-caching the graphql state. Another feature of our environment is that when the app starts we don't have any tenants, although we do have hooks to call functions after new tenants are created (after liquibase migrations have run to create the structure for the tenant). Similarly, I'm not clear yet if all the cached data fetchers will be a problem for us in the (database) Schema-per-tenant environment, and if we really need a (GraphQL) Schema-per-tenant also?

Any thoughts or suggestions? As I said - really happy to try and work through this but need some guidance on where to start.

Cheers.

stacktrace follows::

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'graphQLSchema': Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [graphql.schema.GraphQLSchema]: Factory method 'generate' threw exception; nested exception is org.grails.datastore.mapping.multitenancy.exceptions.TenantNotFoundException: Tenant could not be resolved outside a web request
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1181)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1075)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:84)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:393)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:380)
        at grails.boot.GrailsApp$run.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:136)
        at mod.directory.Application.main(Application.groovy:8)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [graphql.schema.GraphQLSchema]: Factory method 'generate' threw exception; nested exception is org.grails.datastore.mapping.multitenancy.exceptions.TenantNotFoundException: Tenant could not be resolved outside a web request
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
        ... 23 common frames omitted
Caused by: org.grails.datastore.mapping.multitenancy.exceptions.TenantNotFoundException: Tenant could not be resolved outside a web request
        at com.k_int.okapi.OkapiTenantResolver.resolveTenantIdentifier(OkapiTenantResolver.groovy:65)
        at grails.gorm.multitenancy.Tenants.currentId(Tenants.groovy:73)
        at org.grails.datastore.gorm.GormEnhancer.findTenantId(GormEnhancer.groovy:270)
        at org.grails.datastore.gorm.GormEnhancer.findStaticApi(GormEnhancer.groovy:296)
        at org.grails.gorm.graphql.fetcher.DefaultGormDataFetcher.<init>(DefaultGormDataFetcher.groovy:51)
        at org.grails.gorm.graphql.fetcher.DefaultGormDataFetcher.<init>(DefaultGormDataFetcher.groovy:44)
        at org.grails.gorm.graphql.fetcher.impl.SingleEntityDataFetcher.<init>(SingleEntityDataFetcher.groovy)
        at org.grails.gorm.graphql.Schema.generate(Schema.groovy:266)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
        ... 24 common frames omitted

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions