Open dpisarewski opened 9 years ago
What do you think the default behavior should be? I guess it should mark the transaction as expired once this error occurs so it doesn't bother attempting to continue, right?
Well, I expect that by calling Neo4j::Transaction.current
I won't get an expired transaction. It could also update the value of 'expires' since neo4j rest api always returns it.
http://neo4j.com/docs/stable/rest-api-transactional.html#rest-api-execute-statements-in-an-open-transaction-in-rest-format-for-the-return
But if your transaction has expired, shouldn't it give you an error so you can react to it? We could definitely add an expired?
instance method that compares the current time to the transaction's expiration, too.
I agree that all requests inside an invalid transaction must fail. But when you already know the transaction is invalid then you don't need to send requests to the database. They could fail without touching the database due to expired transaction.
Furthermore, in this case we also know the transaction is already closed on the server. So after throwing an exception it Neo4j::Transaction.current
should be available for registering a new transaction without calling close
method on the expired transaction.
So once we get a response saying that a transaction is expired, it should mark it, expired?
should return true, and all attempts to communicate with the server using that transaction object should fail. If we already know that the transaction is invalid, we shouldn't be wasting time trying to reuse it -- I'm with you there. I don't want to examine the expiration timestamp on each action, though... This should be reactive, not proactive.
But are you saying that it should automatically create a new transaction so that Neo4j::Transaction.current
returns a valid object?
No, I think Neo4j::Transaction.current
should be nil as there is no valid transaction. And I should be able to create a new transaction and get this transaction by calling Neo4j::Transaction.current
.
Example for firing request on invalid transaction:
def test
tx = Neo4j::Transaction.new
sleep 60 #long running operation
User.create
rescue
tx.failure
ensure
tx.close #bang! Neo4j::Server::Resource::ServerException
end
test
Example for unregistered expired transaction:
#first context(code can't be changed)
def call
SecondContext.start
AnotherContext.make_changes #bang!
SecondContext.finalize #won't execute
end
#second context
def start
@tx = Neo4j::Transaction.new
rescue
@tx.failure
end
def finalize
@tx.close rescue nil
end
#another context
def make_changes
sleep 60 #long running operation
SomeNode.create #bang!
end
According to the second example, the invalid transaction won't be closed and the next call will also fail.
Maybe I'm wrong and neo4j-core should not be responsible for removing expired transactions.
I don't really know... I think the question is whether current
represents a transaction with the server or a transaction object within the app. As far as I'm concerned, it's an object within the app, so user owns it and it's up to them to be aware of its state. Once a transaction is failed or expired, the state of the object changes, but their current transaction object still exists.
But I do think that we should maybe subclass CypherTransaction
, maybe FailedCypherTransaction
or both that and ExpiredCypherTransaction
, automatically created and assigned to current
when the state of a transaction changes. It'll give more control over behavior and make it easier for users to identify and react to error states.
That sounds good.
I'm not going to add a new class for failed transactions right now, a little too much going on. I was going to modify the behavior to prevent continued queries within a transaction that's already been marked failed but just noticed this:
it 'can continue operations after transaction is rolled back' do
node = Neo4j::Node.create(name: 'andreas')
Neo4j::Transaction.run do |tx|
tx.failure
node[:name] = 'foo'
expect(node[:name]).to eq('foo')
end
expect(node['name']).to eq('andreas')
end
Interesting that it's deliberate.
Since we know that you can't do anything at all with an expired transaction, as soon as an error comes back stating that the transaction is expired, it will be marked and subsequent queries will not run.
We can play with a new class for failed transactions if you want. I think the next release is gonna be 4.0 so now is a good opportunity to change the API.
Here is it. https://github.com/neo4jrb/neo4j-core/pull/156
Transaction
does not update expiration timestamp and does not unregister expired transaction.