This is an automated email from the ASF dual-hosted git repository.

kenhuuu pushed a commit to branch TINKERPOP-3217
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 0d18110f79ad38428cd40e42f00d13d2abbb8137
Author: Ken Hu <[email protected]>
AuthorDate: Mon Dec 1 12:16:13 2025 -0800

    TINKERPOP-3217 Add server option to close Session automatically.
    
    The added destroySessionPostGraphOp setting enables re-using the same
    underlying connection for a different subsequent Session. This should
    increase performance for cases where many short-lived Transactions are
    sent to the server.
---
 CHANGELOG.asciidoc                                     |  2 ++
 docs/src/reference/gremlin-applications.asciidoc       |  1 +
 .../org/apache/tinkerpop/gremlin/server/Settings.java  |  8 ++++++++
 .../gremlin/server/handler/AbstractSession.java        |  4 ++++
 .../gremlin/server/op/session/SessionOpProcessor.java  | 18 ++++++++++++++++++
 5 files changed, 33 insertions(+)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index b292f8939a..350b26e5da 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -22,7 +22,9 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 [[release-3-7-6]]
 === TinkerPop 3.7.6 (NOT OFFICIALLY RELEASED YET)
+
 * Integrated Python driver examples into automated build process to ensure 
examples remain functional.
+* Added `destroySessionPostGraphOp` to the Gremlin Server settings to indicate 
that the `Session` should be closed on either a successful commit or rollback.
 
 [[release-3-7-5]]
 === TinkerPop 3.7.5 (Release Date: November 12, 2025)
diff --git a/docs/src/reference/gremlin-applications.asciidoc 
b/docs/src/reference/gremlin-applications.asciidoc
index 0eee376fab..4143bbfa76 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -1015,6 +1015,7 @@ The following table describes the various YAML 
configuration options that Gremli
 |authorization.authorizer |The fully qualified classname of an `Authorizer` 
implementation to use. |_none_
 |authorization.config |A `Map` of configuration settings to be passed to the 
`Authorizer` when it is constructed.  The settings available are dependent on 
the implementation. |_none_
 |channelizer |The fully qualified classname of the `Channelizer` 
implementation to use.  A `Channelizer` is a "channel initializer" which 
Gremlin Server uses to define the type of processing pipeline to use.  By 
allowing different `Channelizer` implementations, Gremlin Server can support 
different communication protocols (e.g. WebSocket). |`WebSocketChannelizer`
+|destroySessionPostGraphOp |Controls whether a `Session` will be closed by the 
server after a successful TX_COMMIT or TX_ROLLBACK bytecode request. |_false_
 |enableAuditLog |The `AuthenticationHandler`, `AuthorizationHandler` and 
processors can issue audit logging messages with the authenticated user, remote 
socket address and requests with a gremlin query. For privacy reasons, the 
default value of this setting is false. The audit logging messages are logged 
at the INFO level via the `audit.org.apache.tinkerpop.gremlin.server` logger, 
which can be configured using the `logback.xml` file. |_false_
 |graphManager |The fully qualified classname of the `GraphManager` 
implementation to use.  A `GraphManager` is a class that adheres to the 
TinkerPop `GraphManager` interface, allowing custom implementations for storing 
and managing graph references, as well as defining custom methods to open and 
close graphs instantiations. To prevent Gremlin Server from starting when all 
graphs fails, the `CheckedGraphManager` can be used.|`DefaultGraphManager`
 |graphs |A `Map` of `Graph` configuration files where the key of the `Map` 
becomes the name to which the `Graph` will be bound and the value is the file 
name of a `Graph` configuration file. |_none_
diff --git 
a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
 
b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
index 50e7444b2f..e293a40d1e 100644
--- 
a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
+++ 
b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
@@ -189,6 +189,14 @@ public class Settings {
      */
     public boolean strictTransactionManagement = false;
 
+    /**
+     * If set to {@code true} the Gremlin Server will destroy the session when 
a GraphOp (commit or rollback) is
+     * successfully completed on that session.
+     *
+     * NOTE: Defaults to false in 3.7.6/3.8.1 to prevent breaking change.
+     */
+    public boolean destroySessionPostGraphOp = false;
+
     /**
      * The full class name of the {@link Channelizer} to use in Gremlin Server.
      */
diff --git 
a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
 
b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
index 6680127d51..5b93bf9f7d 100644
--- 
a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
+++ 
b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
@@ -699,6 +699,10 @@ public abstract class AbstractSession implements Session, 
AutoCloseable {
                             .code(ResponseStatusCode.NO_CONTENT)
                             .statusAttributes(attributes)
                             .create());
+
+                if (sessionTask.getSettings().destroySessionPostGraphOp) {
+                    close();
+                }
             } else {
                 throw new IllegalStateException(String.format(
                         "Bytecode in request is not a recognized graph 
operation: %s", bytecode.toString()));
diff --git 
a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
 
b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
index e10a0f1dd0..b9f9ca08b7 100644
--- 
a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
+++ 
b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
@@ -141,6 +141,9 @@ public class SessionOpProcessor extends 
AbstractEvalOpProcessor {
         }};
     }
 
+    // Determines whether to destroy the session after a successful 
COMMIT/ROLLBACK. Set during init().
+    private boolean destroySessionPostGraphOp;
+
     public SessionOpProcessor() {
         super(false);
     }
@@ -154,6 +157,7 @@ public class SessionOpProcessor extends 
AbstractEvalOpProcessor {
     public void init(final Settings settings) {
         this.maxParameters = (int) 
settings.optionalProcessor(SessionOpProcessor.class).orElse(DEFAULT_SETTINGS).config.
                 getOrDefault(CONFIG_MAX_PARAMETERS, DEFAULT_MAX_PARAMETERS);
+        this.destroySessionPostGraphOp = settings.destroySessionPostGraphOp;
     }
 
     /**
@@ -546,6 +550,13 @@ public class SessionOpProcessor extends 
AbstractEvalOpProcessor {
                                 .statusAttributes(attributes)
                                 .create());
 
+                        if (destroySessionPostGraphOp) {
+                            // Setting force to true prevents deadlock when 
this thread attempts to destroy the session.
+                            // This should be safe since either a commit or 
rollback just finished so the transaction
+                            // shouldn't be open.
+                            session.manualKill(true);
+                        }
+
                     } catch (Throwable t) {
                         onError(graph, context);
                         // if any exception in the chain is TemporaryException 
or Failure then we should respond with the
@@ -571,6 +582,13 @@ public class SessionOpProcessor extends 
AbstractEvalOpProcessor {
                                     .statusMessage(t.getMessage())
                                     .statusAttributeException(t).create());
                         }
+
+                        if (destroySessionPostGraphOp) {
+                            // Destroy the session after a successful rollback 
due to error. Placed here rather than
+                            // in a finally block since we don't want to end 
the session if no commit/rollback succeeded.
+                            session.manualKill(true);
+                        }
+
                         if (t instanceof Error) {
                             //Re-throw any errors to be handled by and set as 
the result the FutureTask
                             throw t;

Reply via email to