-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Have Loaders use suspend functions instead of CompletableFutures which integrates with the scope cancellation work in LC 1.14.x Note that due to the way `java-dataloader` works, the model fetcher functions can't be async/suspend functions, as we need the dataloader.load() invocation to happen synchronously to ensure they preceed any dispatch() calls; otherwise queries can hang forever, similar to: graphql-java/java-dataloader#54 Add tests to validate the suspend function implemented loaders and existing model fetchers work properly.
- Loading branch information
1 parent
06421ca
commit b0e1201
Showing
22 changed files
with
751 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
...r/src/main/kotlin/com/joe/quizzy/server/graphql/dataloaders/CoroutineMappedBatchLoader.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.joe.quizzy.server.graphql.dataloaders | ||
|
||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.GlobalScope | ||
import kotlinx.coroutines.future.future | ||
import org.dataloader.BatchLoaderEnvironment | ||
import org.dataloader.MappedBatchLoaderWithContext | ||
import java.util.concurrent.CompletionStage | ||
|
||
abstract class CoroutineMappedBatchLoader<K, V> : MappedBatchLoaderWithContext<K, V> { | ||
|
||
private fun scope(environment: BatchLoaderEnvironment): CoroutineScope { | ||
return (environment.getContext() as? CoroutineScope) ?: GlobalScope | ||
} | ||
|
||
abstract suspend fun loadSuspend(keys: Set<K>, environment: BatchLoaderEnvironment): Map<K, V> | ||
|
||
override fun load(keys: Set<K>, environment: BatchLoaderEnvironment): CompletionStage<Map<K, V>> { | ||
return scope(environment).future { | ||
loadSuspend(keys, environment) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
server/src/test/kotlin/com/joe/quizzy/server/graphql/dataloaders/BatchQuestionLoaderTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.joe.quizzy.server.graphql.dataloaders | ||
|
||
import assertk.assertThat | ||
import assertk.assertions.isEqualTo | ||
import com.joe.quizzy.api.models.Question | ||
import com.joe.quizzy.persistence.api.QuestionDAO | ||
import com.trib3.testing.LeakyMock | ||
import kotlinx.coroutines.future.await | ||
import kotlinx.coroutines.runBlocking | ||
import org.dataloader.BatchLoaderEnvironment | ||
import org.easymock.EasyMock | ||
import org.testng.annotations.Test | ||
import java.time.OffsetDateTime | ||
import java.util.UUID | ||
|
||
class BatchQuestionLoaderTest { | ||
@Test | ||
fun testQuestionLoader() = runBlocking { | ||
val questionDAO = LeakyMock.mock<QuestionDAO>() | ||
val mockEnv = LeakyMock.mock<BatchLoaderEnvironment>() | ||
val loader = BatchQuestionLoader(questionDAO) | ||
val now = OffsetDateTime.now() | ||
val questions = listOf( | ||
Question(UUID.randomUUID(), UUID.randomUUID(), "q1", "a1", "r1", now, now), | ||
Question(UUID.randomUUID(), UUID.randomUUID(), "q2", "a2", "r2", now, now), | ||
Question(UUID.randomUUID(), UUID.randomUUID(), "q3", "a3", "r3", now, now) | ||
) | ||
EasyMock.expect(questionDAO.get(EasyMock.anyObject<List<UUID>>() ?: listOf())).andReturn(questions) | ||
EasyMock.expect(mockEnv.getContext<Any?>()).andReturn(null) | ||
EasyMock.replay(questionDAO, mockEnv) | ||
val qs = loader.load(questions.mapNotNull { it.id }.toSet(), mockEnv).await() | ||
assertThat(qs).isEqualTo(questions.associateBy { it.id }) | ||
EasyMock.verify(questionDAO, mockEnv) | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
server/src/test/kotlin/com/joe/quizzy/server/graphql/dataloaders/BatchUserLoaderTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.joe.quizzy.server.graphql.dataloaders | ||
|
||
import assertk.assertThat | ||
import assertk.assertions.isEqualTo | ||
import com.joe.quizzy.api.models.User | ||
import com.joe.quizzy.persistence.api.UserDAO | ||
import com.trib3.testing.LeakyMock | ||
import kotlinx.coroutines.future.await | ||
import kotlinx.coroutines.runBlocking | ||
import org.dataloader.BatchLoaderEnvironment | ||
import org.easymock.EasyMock | ||
import org.testng.annotations.Test | ||
import java.util.UUID | ||
|
||
class BatchUserLoaderTest { | ||
@Test | ||
fun testUserLoader() = runBlocking { | ||
val userDAO = LeakyMock.mock<UserDAO>() | ||
val mockEnv = LeakyMock.mock<BatchLoaderEnvironment>() | ||
val loader = BatchUserLoader(userDAO) | ||
val users = listOf( | ||
User(UUID.randomUUID(), UUID.randomUUID(), "joe", "[email protected]", "", false, ""), | ||
User(UUID.randomUUID(), UUID.randomUUID(), "bill", "[email protected]", "", false, "") | ||
) | ||
EasyMock.expect(userDAO.get(EasyMock.anyObject<List<UUID>>() ?: listOf())).andReturn(users) | ||
EasyMock.expect(mockEnv.getContext<Any?>()).andReturn(null) | ||
EasyMock.replay(userDAO, mockEnv) | ||
val us = loader.load(users.mapNotNull { it.id }.toSet(), mockEnv).await() | ||
assertThat(us).isEqualTo(users.associateBy { it.id }) | ||
EasyMock.verify(userDAO, mockEnv) | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
server/src/test/kotlin/com/joe/quizzy/server/graphql/dataloaders/BulkInstanceLoaderTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.joe.quizzy.server.graphql.dataloaders | ||
|
||
import assertk.assertThat | ||
import assertk.assertions.isEqualTo | ||
import com.joe.quizzy.api.models.Instance | ||
import com.joe.quizzy.persistence.api.InstanceDAO | ||
import com.trib3.testing.LeakyMock | ||
import kotlinx.coroutines.future.await | ||
import kotlinx.coroutines.runBlocking | ||
import org.dataloader.BatchLoaderEnvironment | ||
import org.easymock.EasyMock | ||
import org.testng.annotations.Test | ||
import java.util.UUID | ||
|
||
class BulkInstanceLoaderTest { | ||
@Test | ||
fun testInstanceLoader() = runBlocking { | ||
val instanceDAO = LeakyMock.mock<InstanceDAO>() | ||
val mockEnv = LeakyMock.mock<BatchLoaderEnvironment>() | ||
val loader = BulkInstanceLoader(instanceDAO) | ||
val instances = listOf( | ||
Instance(UUID.randomUUID(), "i1", "ACTIVE", ""), | ||
Instance(UUID.randomUUID(), "i2", "ACTIVE", "") | ||
) | ||
EasyMock.expect(instanceDAO.get(EasyMock.anyObject<List<UUID>>() ?: listOf())).andReturn(instances) | ||
EasyMock.expect(mockEnv.getContext<Any?>()).andReturn(null) | ||
EasyMock.replay(instanceDAO, mockEnv) | ||
val insts = loader.load(instances.mapNotNull { it.id }.toSet(), mockEnv).await() | ||
assertThat(insts).isEqualTo(instances.associateBy { it.id }) | ||
EasyMock.verify(instanceDAO, mockEnv) | ||
} | ||
} |
Oops, something went wrong.