fix(server): wait for GRAPH_CREATE event when creating graph on PD path - #3138
fix(server): wait for GRAPH_CREATE event when creating graph on PD path#3138bitflicker64 wants to merge 2 commits into
Conversation
The PD-backed createGraph fired GRAPH_CREATE without awaiting it, so the REST 200 could be written before ContextGremlinServer injected the graph into the Gremlin global bindings, and an immediate Gremlin/Cypher request to the creating server could fail with "Could not rebind [g]". createGraphLocal already waits via notifyAndWaitEvent; this applies the same call on the PD path.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3138 +/- ##
============================================
- Coverage 39.18% 34.68% -4.50%
- Complexity 264 498 +234
============================================
Files 770 781 +11
Lines 65779 66929 +1150
Branches 8726 8923 +197
============================================
- Hits 25774 23214 -2560
- Misses 37244 41139 +3895
+ Partials 2761 2576 -185 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
imbajin
left a comment
There was a problem hiding this comment.
Blocking: yes. Summary: The PD create path now waits for GRAPH_CREATE listeners, but listener failures remain non-fatal and the current head has a failing codecov/project check. Evidence: EventHub.notify() catches listener Throwable at hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/event/EventHub.java:200-205; final gate reports codecov/project FAILURE.
|
|
||
| // Let gremlin server and rest server context add graph | ||
| this.eventHub.notify(Events.GRAPH_CREATE, graph); | ||
| this.notifyAndWaitEvent(Events.GRAPH_CREATE, graph); |
There was a problem hiding this comment.
|
|
||
| // Let gremlin server and rest server context add graph | ||
| this.eventHub.notify(Events.GRAPH_CREATE, graph); | ||
| this.notifyAndWaitEvent(Events.GRAPH_CREATE, graph); |
There was a problem hiding this comment.
Waiting for the GRAPH_CREATE future was not enough to prove that the graph was actually registered: EventHub swallows every throwable raised by a listener and resolves the future with the number of listeners that returned normally, so a listener that blew up looked exactly like a successful one. The create now compares the notified count with the registered listener count and fails when a listener did not complete. The wait is also bounded now instead of blocking forever, and an InterruptedException restores the thread's interrupt status before the failure is reported. Ordering is fixed along with it. On the PD path the graph is bound in the local gremlin/rest server context before its config is written to meta and broadcast, so a failed binding cannot leave a graph behind in meta for the other servers to converge on. A binding failure now unregisters the graph locally and closes it, the same cleanup a failed backend init already does, rather than dropping data that other servers may have bound successfully. On the local path the notify moved inside the existing try, which now also unregisters the graph before dropping it, so a failed binding leaves no closed graph behind in the context. The drop path keeps the lenient behaviour: the data is already gone when the event fires, so failing the request cannot undo anything and the listener state may legitimately be absent already.
Purpose of the PR
In distributed mode (PD + HStore),
POST /graphspaces/{space}/graphs/{name}returns 200 before the creating server has actually bound the new graph into its embedded Gremlin server.GraphManager.createGraph(PD path) firesGRAPH_CREATEviathis.eventHub.notify(...), which is asynchronous, so the REST response can be written beforeContextGremlinServerinjects the graph and itsTraversalSourceinto the Gremlin global bindings. An immediate follow-up Gremlin/Cypher request to the same server then fails with HTTP 400:Could not rebind [g] to [__g_<name>] as [__g_<name>] could not be found in the Graph or TraversalSource global bindings.The local path already handles this correctly:
createGraphLocalcallsthis.notifyAndWaitEvent(Events.GRAPH_CREATE, graph), which blocks on the event future before returning. The PD path simply lost that parity.Main Changes
GraphManager.createGraph(PD path): replacethis.eventHub.notify(Events.GRAPH_CREATE, graph)withthis.notifyAndWaitEvent(Events.GRAPH_CREATE, graph), matching whatcreateGraphLocalalready does.GRAPH_CREATElisteners (Gremlin bindings injection included). Cross-replica convergence (other servers picking the graph up via the PD/meta watch) is intentionally out of scope here; that is phase 2/3 of [Feature] Orchestrate graph creation through PD: new graphs are not consistently available across Server replicas ("Could not rebind [g]") #3137.One question for reviewers, as raised in #3137:
notifyAndWaitEvent(GraphManager.java, around line 1774) waits on the event future but swallows listener failures with only aLOG.warn, so a failed bindings injection would still return 200. Should a listener failure fail the create instead? I left that behavior unchanged here to keep this PR a pure parity fix withcreateGraphLocal.Verifying these changes
Does this PR potentially affect the following parts?
Documentation Status
Doc - TODODoc - DoneDoc - No Need