-
Notifications
You must be signed in to change notification settings - Fork 31
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
feat(graphql): prototyping #783
Conversation
6ae55a8
to
e37ac93
Compare
965a192
to
49fcb30
Compare
7e008e6
to
d4087a1
Compare
@hareetd @jan-law @ebaron any questions/thoughts/concerns about GraphQL and the capabilities we have with it so far in this draft? (The code is a mess - it definitely should not just all be stuffed into a GraphModule, so before merging any of this I would refactor it out and split it up in some way generally similar to how the HttpModule and RequestHandlers are.) |
Also, this looks like a reasonable approach to the TODO I have left in https://www.yld.io/blog/query-by-2-or-more-fields-on-graphql/ I'm still not sure if this should be an |
src/main/java/io/cryostat/net/web/http/api/beta/graph/GraphModule.java
Outdated
Show resolved
Hide resolved
src/main/java/io/cryostat/net/web/http/api/beta/graph/GraphModule.java
Outdated
Show resolved
Hide resolved
Just had a neat idea to really use the power of the GraphQL engine to our advantage here, after I've gone through and done some refactoring and cleanup to make this more presentable. Check it out:
query {
targetsDescendedFrom(nodes: [{ name: "service:jmx:rmi:///jndi/rmi://cryostat:9093/jmxrmi", nodeType: "JVM" }]) {
name
nodeType
target {
alias
serviceUri
labels
annotations {
platform
cryostat
}
}
recordings {
active {
name
downloadUrl
reportUrl
state
startTime
duration
continuous
toDisk
maxSize
maxAge
}
archived {
name
downloadUrl
reportUrl
}
}
startRecording(recording: {
name: "foo",
template: "Profiling",
templateType: "TARGET",
duration: 30
}) {
name
downloadUrl
reportUrl
state
startTime
duration
continuous
toDisk
maxSize
maxAge
}
}
} This happens to be specifying a specific target node (the 9093 vertx-fib-demo) as the node whose descendants should be queried, so in this case the list of target descendants is trivially just the singleton list of the specified node itself. The query will be carried out against all of the nodes in that list and it will return a whack of information about each of those nodes, like its name and type and labels, etc. The GraphQL engine will also call another data fetcher to resolve the Most notably and new in the latest commit is the Speaking of response, here's what the response to the big query above looks like: {
"data": {
"targetsDescendedFrom": [
{
"name": "service:jmx:rmi:///jndi/rmi://cryostat:9093/jmxrmi",
"nodeType": "JVM",
"recordings": {
"active": [],
"archived": []
},
"startRecording": {
"continuous": false,
"downloadUrl": "https://localhost:8181/api/v1/targets/service:jmx:rmi:%2F%2F%2Fjndi%2Frmi:%2F%2Fcryostat:9093%2Fjmxrmi/recordings/foo",
"duration": 30000,
"maxAge": 0,
"maxSize": 0,
"name": "foo",
"reportUrl": "https://localhost:8181/api/v1/targets/service:jmx:rmi:%2F%2F%2Fjndi%2Frmi:%2F%2Fcryostat:9093%2Fjmxrmi/reports/foo",
"startTime": 1643340857661,
"state": "RUNNING",
"toDisk": true
},
"target": {
"alias": "es.andrewazor.demo.Main",
"annotations": {
"cryostat": {
"HOST": "cryostat",
"JAVA_MAIN": "es.andrewazor.demo.Main",
"PORT": "9093"
},
"platform": {}
},
"labels": {},
"serviceUri": "service:jmx:rmi:///jndi/rmi://cryostat:9093/jmxrmi"
}
}
]
}
} We can see that the active recordings list is empty, so this means (and this is also supported by the logs) that the read part of the query was executed before the mutation part. But if we simply reorder the components of the query then we can cause the mutation to happen first so that the query includes that result as well. query {
targetsDescendedFrom(nodes: [{ name: "service:jmx:rmi:///jndi/rmi://cryostat:9093/jmxrmi", nodeType: "JVM" }]) {
startRecording(recording: {
name: "bar",
template: "Profiling",
templateType: "TARGET",
duration: 30
}) {
name
downloadUrl
reportUrl
state
startTime
duration
continuous
toDisk
maxSize
maxAge
}
name
nodeType
target {
alias
serviceUri
labels
annotations {
platform
cryostat
}
}
recordings {
active {
name
downloadUrl
reportUrl
state
startTime
duration
continuous
toDisk
maxSize
maxAge
}
archived {
name
downloadUrl
reportUrl
}
}
}
} {
"data": {
"targetsDescendedFrom": [
{
"name": "service:jmx:rmi:///jndi/rmi://cryostat:9093/jmxrmi",
"nodeType": "JVM",
"recordings": {
"active": [
{
"continuous": false,
"downloadUrl": "https://localhost:8181/api/v1/targets/service:jmx:rmi:%2F%2F%2Fjndi%2Frmi:%2F%2Fcryostat:9093%2Fjmxrmi/recordings/foo",
"duration": 30000,
"maxAge": 0,
"maxSize": 0,
"name": "foo",
"reportUrl": "https://localhost:8181/api/v1/targets/service:jmx:rmi:%2F%2F%2Fjndi%2Frmi:%2F%2Fcryostat:9093%2Fjmxrmi/reports/foo",
"startTime": 1643340857661,
"state": "STOPPED",
"toDisk": true
},
{
"continuous": false,
"downloadUrl": "https://localhost:8181/api/v1/targets/service:jmx:rmi:%2F%2F%2Fjndi%2Frmi:%2F%2Fcryostat:9093%2Fjmxrmi/recordings/bar",
"duration": 30000,
"maxAge": 0,
"maxSize": 0,
"name": "bar",
"reportUrl": "https://localhost:8181/api/v1/targets/service:jmx:rmi:%2F%2F%2Fjndi%2Frmi:%2F%2Fcryostat:9093%2Fjmxrmi/reports/bar",
"startTime": 1643341706359,
"state": "RUNNING",
"toDisk": true
}
],
"archived": []
},
"startRecording": {
"continuous": false,
"downloadUrl": "https://localhost:8181/api/v1/targets/service:jmx:rmi:%2F%2F%2Fjndi%2Frmi:%2F%2Fcryostat:9093%2Fjmxrmi/recordings/bar",
"duration": 30000,
"maxAge": 0,
"maxSize": 0,
"name": "bar",
"reportUrl": "https://localhost:8181/api/v1/targets/service:jmx:rmi:%2F%2F%2Fjndi%2Frmi:%2F%2Fcryostat:9093%2Fjmxrmi/reports/bar",
"startTime": 1643341706359,
"state": "RUNNING",
"toDisk": true
},
"target": {
"alias": "es.andrewazor.demo.Main",
"annotations": {
"cryostat": {
"HOST": "cryostat",
"JAVA_MAIN": "es.andrewazor.demo.Main",
"PORT": "9093"
},
"platform": {}
},
"labels": {},
"serviceUri": "service:jmx:rmi:///jndi/rmi://cryostat:9093/jmxrmi"
}
}
]
}
} |
a49a7e9
to
a23c33e
Compare
Here are some resources following up from yesterday's discussion: https://stackoverflow.com/questions/46160002/graphql-cascade-deletion https://graphql-api.com/guides/schema/using-nested-mutations/ https://blog.logrocket.com/supporting-opt-in-nested-mutations-in-graphql/ |
c1dcf14
to
59b5126
Compare
…node could be used to allow more of the fetching and querying structure to be handled by the graphql engine and less by application code - just build fetchers to look for targets with various simple methods (all descendents of a specific named/typed node, or all descendents of nodes with a certain label), and give each of those the ability to have a recording started against it
59b5126
to
3a950b2
Compare
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.
Changes seem good to me. Lots of FIXMEs/TODOs throughout, but this is mostly self-contained, so I'm not worried about getting this in and fixing it up later.
I've been looking over this code and playing around with GraphQL on the main branch to refresh my memory before giving input on #825. I decided to try this query out but got an error saying |
You didn't do anything wrong there really, but that old comment is out of date and doesn't reflect what got merged anymore. Generally though, that query was first written for making a top-level query that would select some EnvironmentNode in the tree and return a list of all of its TargetNode children. That got replaced by the top-level
query {
environmentNodes(filter: { name: "JDP" }) {
descendantTargets {
doStartRecording(recording: {
name: "foo",
template: "Profiling",
templateType: "TARGET",
duration: 30
}) {
name
state
}
}
}
} |
Ah makes sense, thanks. |
Related to #495