neo4j / neo4j-dotnet-driver

Neo4j Bolt driver for .NET
Apache License 2.0
222 stars 69 forks source link

Transaction identifier #669

Open Shishkovskiy opened 1 year ago

Shishkovskiy commented 1 year ago

Is there any chance to have the transaction Id or something like that to cancel it in the middle of the process?

thelonelyvulpes commented 1 year ago

Which Transaction exactly do you mean?

The Driver transactions currently represent the state of the transaction on the server, so you can cancel a transaction by not committing it, or throwing an exception if you are using ExecuteRead/ExecuteWrite (previously known as ReadTransaction/WriteTransaction).

That said currently there is not a way to interrupt a query in the driver.

Shishkovskiy commented 1 year ago

I'm talking about driver transactions, let's imagine I need to insert some data into the database, and I'd like to use transactions for it. Besides that, I'd like to have a chance to cancel that transaction in the middle of the process. For instance, I provide some inserting progress to users, and if it takes more time than they expect, they can cancel the transaction. And my question is, is there any way to have a unique identifier for each transaction and then cancel it using a unique identifier?

thelonelyvulpes commented 1 year ago

Hi @Shishkovskiy sorry about the delay responding, I took some time to have a go at how this might work for an application and got side tracked.

You ideally would wrap your transactions to enable cancellation tokens then register your transactions with with some sort of transaction manager. If you use transaction functions (ExecuteReadAsync, ExecuteWriteAsync) throwing an exception in lambda will cause the transaction to be cancelled.

We won't be adding any functionality for this in the driver currently, though we are trying to increase the surface which is cancellation token friendly.

peter-villadsen commented 6 months ago

It would be nice to have the cancellation token that you mention:


CancellationToken token;
...
    using Neo4j.Driver.ISession session = Driver.Session();
    var rrr = session.ExecuteWrite<(List<IRecord>, IResultSummary)>(tx =>
    {
        IResult result = tx.Run(cypherSource, parameters, **token**);
        var records = result.ToList();
        IResultSummary summary = result.Consume();
        return (records, summary);
    });

where the token is cancelled from some button on the UI. The problem then becomes knowing when to enable and disable that button (as when a transaction is running or not).

Right now, it is a real mess dealing with transactions. I ended up using the cypher "show transactions" and "terminate transaction ". This is definitely only a temporary measure, which places unacceptable load on the server, especially since there is no way to get the transactionId when a transaction is started (requiring the "show transactions").

pvillads commented 6 months ago

Let me add one more context to the ticket: I think the cancellation token is the right approach, since it is idiomatic to C#. However, I wonder if it would be a simple orthogonal fix to simply have a property on the transaction instance that shows the same ID as you get from the SHOW TRANSACTION command? At least it would then be possible to use that ID in a TERMINATE TRANSACTION command. Did I fail to find this?

juan-diaz-at-nicklaus commented 2 weeks ago

Hi @pvillads, one way you can achieve that is by attaching metadata to the transaction...

  await session.ExecuteReadAsync(async transaction =>
  {
      ... Code here
  }, (config) => config.WithMetadata(new Dictionary<string, object>() {{ "myId", "TheId" }}));

and then execute something like this...

SHOW TRANSACTIONS YIELD transactionId AS txId, metaData AS md WHERE md.myId = "TheId"
TERMINATE TRANSACTIONS txId
YIELD message
RETURN txId, message

Only make sure you attach info that can be uniquely identified.

Hope that help!

Cheers!