-
Notifications
You must be signed in to change notification settings - Fork 326
Feature: Add data loader reload API for development environments #2200
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
Conversation
paulbakker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this @berngp. Added a few comments, will test further as well.
...kotlin/com/netflix/graphql/dgs/springgraphql/autoconfig/DgsSpringGraphQLAutoConfiguration.kt
Outdated
Show resolved
Hide resolved
| * } | ||
| * ``` | ||
| */ | ||
| interface DgsDataLoaderReloadController { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need an external signal here instead of always reloading like we do for the schema? (when reload is enabled)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case the signal is needed to trigger the post-construct of the DefaultDgsDataLoaderProvider (previously named as DgsDataLoaderProvider). This also allows us to pass a new, or refreshed, application context that will be used to discover the new versions of the Data Loaders.
This also allowed me to minimize the changes to the current DgsDataLoaderProvider in main, just changing its name to DefaultDgsDataLoaderProvider and the interface that it implements. The controller allows us to understand when the DefaultDgsDataLoaderProvider needs to be rebuilt, included the execution of the post-construct.
| /** | ||
| * Framework implementation class responsible for finding and configuring data loaders. | ||
| */ | ||
| class DefaultDgsDataLoaderProvider( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shows as a new file in the diff, but is this a one-to-one copy of the existing code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is, the name changed as well as implementing DgsDataLoaderProvider, but nothing else. I wish the the diff was a bit smarter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the PR, these are the changes agains the original file
- name change from
DgsDataLoaderProvidertoDefaultDgsDataLoaderProvider. - adopt the
DgsDataLoaderProvider. - add the
overridefor the interface APIs. - make sure that the dataloaders know their names when they are created.
58c58
< class DgsDataLoaderProvider(
---
> class DefaultDgsDataLoaderProvider(
66c66
< ) {
---
> ) : DgsDataLoaderProvider {
80c80
< fun buildRegistry(): DataLoaderRegistry = buildRegistryWithContextSupplier { null }
---
> override fun buildRegistry(): DataLoaderRegistry = buildRegistryWithContextSupplier { null }
82c82
< fun <T> buildRegistryWithContextSupplier(contextSupplier: Supplier<T>): DataLoaderRegistry {
---
> override fun <T> buildRegistryWithContextSupplier(contextSupplier: Supplier<T>): DataLoaderRegistry {
232c232
< return DataLoaderFactory.newDataLoader(extendedBatchLoader, options.build())
---
> return DataLoaderFactory.newDataLoader(dataLoaderName, extendedBatchLoader, options.build())
270c270
< return DataLoaderFactory.newDataLoader(extendedBatchLoader, options.build())
---
> return DataLoaderFactory.newDataLoader(dataLoaderName, extendedBatchLoader, options.build())
291c291
< return DataLoaderFactory.newMappedDataLoader(extendedBatchLoader, options.build())
---
> return DataLoaderFactory.newMappedDataLoader(dataLoaderName, extendedBatchLoader, options.build())
302c302,310
< is BatchLoader<*, *> -> createDataLoader(holder.theLoader, holder.annotation, holder.name, registry, extensionProviders)
---
> is BatchLoader<*, *> ->
> createDataLoader(
> holder.theLoader,
> holder.annotation,
> holder.name,
> registry,
> extensionProviders,
> )
>
311a320
>
319a329
>
328a339
>
378c389
< private val logger: Logger = LoggerFactory.getLogger(DgsDataLoaderProvider::class.java)
---
> private val logger: Logger = LoggerFactory.getLogger(DefaultDgsDataLoaderProvider::class.java)
graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/ReloadableDgsDataLoaderProvider.kt
Outdated
Show resolved
Hide resolved
|
I'm in favor of the current implementation in the PR, I would like to stay away from Spring Cloud for this. |
|
Thanks Paul for the review, will address the feedback. |
Implements programmatic mechanism to force reloading of _Data Loaders_, to be used during development without application restart. The implementation provides no overhead when _DGS Reloading_ is disabled. When enabled, it wrapps the current implementation, no called `DefaultDgsDataLoaderProvider` in such a way that a new one is created when the reload is invoked via `DgsDataLoaderReloadController`. It supports either reloading by the current application context or a new one provided through the _force reload_ api. Features: - DgsDataLoaderReloadController public API with statistics tracking - ReloadableDgsDataLoaderProvider wrapping DefaultDgsDataLoaderProvider - @ConditionalOnDgsReload annotation for development-only activation - Zero overhead when disabled (default for non-laptop profiles) - Symmetric functionality with existing schema reload while maintaining safety and not affecting performance characteristics.
6f86a7a to
2101d0b
Compare
Pull Request type
Changes in this PR
DGS Data Loader Reload Support
Implements programmatic mechanism to force reloading of Data Loaders, to be used during development without application restart. The implementation provides no overhead when DGS Reloading is disabled. When enabled, it wrapps the current implementation, no called
DefaultDgsDataLoaderProviderin such a way that a new one is created when the reload is invoked viaDgsDataLoaderReloadController. It supports either reloading by the current application context or a new one provided through the force reload api.Features:
Alternatives considered
Spring Cloud RefreshScope
As an alternative we could leverage Spring Cloud's
@RefreshScopemechanism versus implementing a custom reload solution. This will require a re-architecture of the current supported for the schema, broader changes to the DGS Spring Boot integration, and a direct dependency on Spring Cloud.Spring Cloud RefreshScope Overview
Core Characteristics:
@ConfigurationPropertiesbeans/refreshendpoint or external configuration changesLifecycle Management:
Architectural Decision
Using the
DgsDataLoaderReloadControllerSpring Cloud Example
The current implementation provides an easy way to leverage Spring Cloud's reload mechanism. This could be done as follows...
or