Skip to content

Conversation

@KammererTob
Copy link
Contributor

This an attempt to fix #2068 . It might be a bit too naive, but i wanted to get another set of eyes on this issue.

Here my reasoning for this fix:
As explained in the issue, the problem lies in how the dataloader determines when to dispatch different levels. When one of the resolveFieldWithInfo futures completes exceptionally, the Async.each Future also completes exceptionally and the dataloader instrumentation is not made aware of this. Since expectedStrategyCallsPerLevel is increased by calls to handleOnFieldValuesInfo by previous levels and allOnFieldCallsHappened is checked for the previous level when dispatching, it means that all deeper levels will never be dispatched (expectedStrategyCallsPerLevel is bigger than happenedOnFieldValueCallsPerLevel) and we leak a thread. The changes made make sure that the instrumentation is made aware of this exceptional completion and thus that deeper levels can still be dispatched.

If you have better ideas to fix this i am open for your suggestions! Thanks!

.type(newTypeWiring("Query")
.dataFetcher("pets", new StaticDataFetcher(['cats': cats, 'dogs': dogs])))
.type(newTypeWiring("Cat")
.dataFetcher("toys", new StaticDataFetcher(new List<Object>() {
Copy link
Contributor

@dfa1 dfa1 May 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe a Collections.singletonList is better here? size returns 1, but then toArrray, listIterator returns both null

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my bad, just spotted the "iterator" that throws exception!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KammererTob what about:

			 new java.util.AbstractList<>() {

				@Override
				public int size() {
					return 1;
				}

				@Override
				public Object get(int index) {
					throw new RuntimeException("simulated failure");
				}
			};

by default, the Iterator will call get(), throwing exception, like in your code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback. I've adjusted the code as by your comment and i also renamed the whole test block to better reflect what it is testing.

@bbakerman bbakerman changed the title Fix #2068 Fixes #2068 - Silent thread leak on exception in completeValueForList Jul 5, 2021
@bbakerman bbakerman added this to the 17.0 milestone Aug 3, 2021
@bbakerman bbakerman merged commit a75b54a into graphql-java:master Aug 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Silent thread leak on exception in completeValueForList

3 participants