Skip to content
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

Refactor blueprint to be per service #404

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

gnawf
Copy link
Collaborator

@gnawf gnawf commented Mar 22, 2022

Pending #403 and need to rebase onto master to get Artyom's blueprint changes.

Effectively this change uses the more correct way to collect services types that the validation has been doing i.e. uses getServiceTypes and getReachableTypes to collect all the types a service uses.

This improves the way we handle shared types as blueprints are now per service, which is actually a better view as we only execute the "query" on one service at a time anyway.

Stuff is not final and am happy to discuss this change.

Please make sure you consider the following:

  • Add tests that use __typename in queries
  • Does this change work with all nadel transformations (rename, type rename, hydration, etc)? Add tests for this.
  • Is it worth using hints for this change in order to be able to enable a percentage rollout?
  • Do we need to add integration tests for this change in the graphql gateway?
  • Do we need a pollinator check for this?

@gnawf gnawf changed the base branch from merge/api/engine-nextgen to master March 23, 2022 03:42
@gnawf gnawf force-pushed the nadel-kt/blueprint-refactor branch from b339d66 to 5d78eed Compare March 23, 2022 09:41
underlyingSchema = underlyingSchema,
serviceExecution = serviceExecution,
definitionRegistry = nadelDefinitionRegistry
)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Just reformat

)
private val executionIdProvider = nadel.executionIdProvider
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Above is mostly rearranging stuff and changing constructors to take in Service instead of the now removed NadelOverallExecutionBlueprint.

@@ -180,7 +184,11 @@ class NextgenEngine @JvmOverloads constructor(
service: Service,
executionContext: NadelExecutionContext,
): ExecutionResult {
val executionPlan = executionPlanner.create(executionContext, services, service, topLevelField)
if (service.name == IntrospectionService.name) {
return executeIntrospection(service, topLevelField, executionContext)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Shortcuts introspection so it never runs transforms.

* For now, this is the actual overall schema. But in the future this will be a subset
* of the overall schema that this [Service] contributed.
*/
lateinit var schema: GraphQLSchema
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So I'm thinking, we should really operate on a subset of the overall/engine schema for this specific service. We're always executing a query/top level field in the context of one service. This way we limit the possible types etc to the one service we're operating on, leaving less room for error.

Copy link
Member

Choose a reason for hiding this comment

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

how is this going to work? if service Issues defines a new type

type Issue {
  id: ID
  assignee: User
}

that references a type declared in another service Users, then that part of the overall schema owned by Issues service is not a valid graphql schema (like it's not self contained)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So it'll work by creating a subset of the schema for each service. We already have a pretty good understanding of which types belong to a service (including shared types) by using all the definitions and collecting all the reachable/referenced types.

Basically it won't just look at the .nadel file but beyond that, and then filter the schema by the types reachable by that service.

@@ -1,4 +1,4 @@
package graphql.nadel.engine.blueprint
package graphql.nadel.engine.introspection
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Moved this to its own package since it didn't make sense in the blueprint package.

@@ -182,107 +168,6 @@ internal class NadelTypeValidation(
return false
}

private fun getServiceTypes(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Moved this to NadelGetServicesTypes.kt

return CONTINUE
}

override fun visitGraphQLInterfaceType(
node: GraphQLInterfaceType,
context: TraverserContext<GraphQLSchemaElement>,
): TraversalControl {
add(node.name)
add(node)
addAll(getImplementations(node))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This now collects implementations of the given interface type which is more correct. We were possibly missing out on some validation beforehand.

import graphql.schema.GraphQLSchema
import graphql.schema.GraphQLUnionType

fun getServiceTypes(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copied from NadelTypeValidation

@@ -1,217 +1,130 @@
package graphql.nadel.engine.blueprint
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I would recommend just reading the new version of this file instead of reading the diff.

The creation of field instructions hasn't changed much. The main change is the process of collecting service types, which now follows the more correct process that validation uses.

Blueprints are also now per service. This will accommodate shared types better and avoids the need to keep passing in the service to blueprint functions.

@@ -255,7 +269,6 @@ class NextgenEngine @JvmOverloads constructor(
): Pair<NadelQueryTransformer.TransformResult, NadelExecutionPlan> {
val executionPlan = executionPlanner.create(
executionContext,
services,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Moved to constructor

@gnawf gnawf marked this pull request as ready for review March 24, 2022 03:18
@@ -36,7 +36,7 @@ val File.parents: Sequence<File>
* Set this to true to run the query. You'll have to modify the [ServiceExecutionFactory] to
* actually return something e.g. response from Splunk etc.
*/
const val runQuery = false
const val runQuery = true
Copy link
Member

Choose a reason for hiding this comment

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

hey, is this deliberate? the doco above says the default is `false

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yup mistake, I'll fix revert it.

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.

2 participants