-
Notifications
You must be signed in to change notification settings - Fork 68
1.2 Driver documentation
This document servers as a supplementary documents to our official driver documentation. If you have not read the official documentation yet, read that one first.
This document aims to provide an introduction to how to use the 1.2 driver by giving examples with additional explanation of how the driver is internally implemented. This document will NOT cover how to write Cypher or how to set up this driver in Azure or AWS.
This document is still under heavy construction and it is drafted by a terrible English writer. Have fun reading :)
This driver requires .NET core 1.3 or .NET framework 4.6+ support.
The main goal of 1.2 driver is to provide improved user experience with Neo4j Causal Cluster. To achieve this goal, the 1.2 driver provides improved Causal Clustering API. The improved API which
- automates the passing of causal consistency context (bookmark) within Sessions
- hides failures that are caused by cluster leader switch by replay transactions using the strategy defined by retry logic
- prevents driver death when the database service is completely unavailable
When reading this section, we assume that you already have some basic knowledge of what is a Neo4j Causal Cluster, and what is Leader
/Core
/Read-replica
member in a Casual Cluster.
var driver = GraphDatabase.Driver( "bolt+routing://localhost:7687" );
A driver is thread-safe. It is recommended to use the driver in a singleton pattern. The driver maintains a connection pool to the servers that are currently known to the driver. The pool manages connections that could be claimed by sessions and transactions on demands. There is no maximum limitation on how many connections that could be created by the connection pool. While there is a config setting Config.MaxIdleSessionPoolSize
(Badly named, it should be that an application user could modify to decide how many connections with each server that could be buffered in the pool. Setting this config to MaxIdleConnectionPoolSize
)0
will turn off pooling of connections with all servers.
"bolt+routing://localhost:7687"
When creating the driver, an initial Uri is provided to the driver. In the initial Uri, scheme bolt+routing
should be used for a driver with built-in routing to a Neo4j Causal Cluster.
The initial Uri directs the driver to a server in the cluster where the driver could inquire a routing table
. A routing table carries routing information to cluster members and the roles of the cluster members. Using the routing information returned in the routing table, a connection pool for pooling connections to the cluster is then generated. Note: The server that could accept the inquiration of routing table are only the Core
members (a.k.a. routers
).
The roles of cluster members in a routing table could be routers
(where a routing table could be inquired), readers
(where read statements could be executed) and writers
(where write statements could be executed). After the first routing table is received, the driver will start to use the newly returned routers for updating routing tables.
While if the driver ever runs out of routers (the driver failed to contact any of the router in a routing table) due to some errors inside the cluster (such as restart of the cluster), the driver will fall back to contract the server indicted by the initial Uri for a new routing table to recover from no router problem.
Note: this driver currently dose NOT support resolving DNS to IP addresses at connection pool level.
var driver = GraphDatabase.Driver( "bolt+routing://localhost:7687", myAuthToken,
new Config{EncryptionLevel= EncryptionLevel.None} );
If the server have authentication enabled (dbms.security.auth_enabled=true
), then the driver should also authenticate itself to the server with the correct Neo4j login username and password.
Driver accepts a config where application users could modify the driver according to their application requirement. Read the API doc of Config class for more information.
driver.Dispose();
When disposing a driver, all connections (both idle connections in the connection pool and connections used by on going sessions and transactions) will be closed. After the driver disposed, no more connections could be created.
using(var session = driver.Session(defaultAccessMode, bookmark))
{
session.Run(cypherStatement);
}
In 1.2 driver, session holds a defaultAccessMode
attribute which are used by session.Run
and session.BeginTransaction
to decide which server (readers or writers) to execute cypher statements.
While despite of the defaultAccessMode
that is given to the session, the method session.WriteTransaction
will always try to run a transaction on a write server. Similarly, the method session.ReadTransaction
will always try to run on a read server. The example code bellow shows a session with default Read
access mode could run a write statement in session.WriteTransaction
:
using(var session = driver.Session(AccessMode.Read))
{
session.WriteTransaction((tx)=>tx.Run(cypherStatement));
}
Note: A session is not thread-safe. Do NOT assign one session to two concurrent threads.
string bookmark = null;
using(var session = driver.Session())
{
session.WriteTransaction(tx=>tx.Run("CREATE (n:Node)"));
var result = session.ReadTransaction(tx=>tx.Run("MATCH (n) RETURN count(n)"));
assertDatabaseNotEmpty(result);
bookmark = session.LastBookmark;
}
using(var session = driver.Session(bookmark: bookmark))
{
var result = session.ReadTransaction(tx=>tx.Run("MATCH (n) RETURN count(n)"));
assertDatabaseNotEmpty(result);
}
When creating a session, the driver.Session
method also accepts a parameter called bookmark
. A bookmark is a reference to a previous transaction. In a Causal Cluster, when starting a new transaction, we might want to make sure that the server hosting the new transaction is at least as up-to-date as the transaction referenced by a bookmark.
When running multiple transactions inside a session, a new transaction is guaranteed to see the transactions that have been committed in the same session (a.k.a. Causal Consistency
). To guarantee the order between sessions, we pass the bookmark between sessions. The latest bookmark of a session could be obtained via field called session.LastBookmark
.
Only successful explicit transactions in a session could update the LastBookmark
inside a session, which suggests:
- a failing transaction will not change
LastBookmark
inside a session, - statement run in
sesison.Run
method has nothing to do withLastBookmark
.
1.2 driver introduces two new methods ReadTransaction
and WriteTransaction
. They take Action<ITransaction>
or Func<ITransaction, T>
as input where a transaction tx
is exposed for running cypher statements. The statements run inside the exposed transaction will be retried using our built-in retry logic if some specific recoverable errors happens (See more in RetryLogic).
When using retries, make sure that your statements inside retries are idempotent to avoid commit multiple times due to errors that might happen during commit, such as loss of Internet connection.
These are the two methods that come with driver since 1.0. However after reading previous sections, it is not hard to notice that these two methods have limited uses on a driver for Neo4j Causal Cluster.
A statement executed by a session.Run
method:
- does not participate in Causal Consistency in a session,
- cannot be retried using driver built-in retry logic when cluster instability error happens.
A statement run by a transaction obtained via session.BeginTransaction
method:
- cannot be replayed when cluster instability error happens.
While session.Run
still provides a quick way to run a statement and session.BeginTransaction
gives access to a transaction for application users to build their own error handling logic.
The result is lazied pulled at the time when they are iterated. If the result of previously executed statement in a session is not iterated, but the session is used for a new statement execution, then the result of the previous statement will be buffered.
Checkout official driver documentation