Allow loaders to be used without an executor #35
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
@rmosolgo, @xuorig & @cjoudrey
Problem
As pointed out in #33 (comment), when using graphql-batch outside of the execution strategy, we run the risk of leaky state. This could be a problem when using the graphql gem's new lazy resolution API, but it could also be a problem in tests.
As such, I think we should move away from depending on global state, even if we support one for convenience and backwards compatibility.
The thread local executor is used for three purposes right now:
Solution
promise.rb 0.7.2 now keeps track of the source of the promise and uses that to sync the promise by default. All that is needed to use that is to set the promise source on the promise returned by the loader's load method.
Without the need to use the executor for resolve the promises, we could then create per request loaders as documented in the dataloader README which could then be stored in the graphql query context. Doing this also allows loaders' cache to be used after their batch load is performed. However, this does bring the concern of cache invalidation if the loaders are used across top-level mutation fields.
For now the loading flag is kept on the executor and is just not updated when there is no current executor. That could be fixed in the future by moving the flag outside of the executor into it's own thread-local variable, but will more likely be replaced by a more generic instrumentation hook.
Follow-up
I plan on having the executor not get created automatically and require the code using the library to specify where batching starts and stops using a block. E.g.
would setup the executor for the block and pass the result of the block to
Promise.sync