[ST-1518] Remove transaction handling from potion.#14
Conversation
678208c to
ea52d40
Compare
|
I forgot to add tests. They will come soon, but it has already been tested with kompost. So I assume the code won't change. |
|
@ticosax what is the problem we are trying to fix? also why the nested transaction? |
|
That is necessary because we took the decision to let flask decides globally about to commit or rollback the transaction That's a liberty that flask-sqlalchemy offers, for some case it works, but not for us. As we chose to not rely on the We are trying to take control over the transactions/savepoints. We want to have control over the boundaries and the lifetime of the transactions. When external dependencies like potion are explicitly committing/rollback-ing, they prevent our business logic to be supported. Today this snippet, doesn't work. assert not Model.query.count()
response = client.post()
assert response.status_code == 400
assert not Model.query.count() # AssertionError 1 is Truewith a modified version of https://github.com/infarm/kompost/pull/2028 + this PR it will. |
|
|
||
| def create(self, properties): | ||
| session = self._get_session() | ||
| with session.begin_nested(): |
There was a problem hiding this comment.
there's a double try/except.
The one inside our code, then the one inside the with (https://github.com/sqlalchemy/sqlalchemy/blob/6a622c636ca5bc55d96b92652fd43b914a77645c/lib/sqlalchemy/engine/base.py#L1764).
Not to sure we need the one here.
There was a problem hiding this comment.
The one in potion is to transform the exception and detect the conflict. In any case potion is raising an exception if one is triggered. It means in terms of transaction management, the context manager of sqlalchemy is the solely decision maker. the potion's one doesn't interfere with that.
It should be framework decision, not lib decision
ea52d40 to
2d88ed0
Compare
|
I remove the signal handlers outside the savepoint. |
| raise BackendConflict( | ||
| debug_info=dict( | ||
| exception_message=str(e), statement=e.statement, params=e.params | ||
| with session.begin_nested(): |
There was a problem hiding this comment.
To summarize my understanding.
We want to avoid having Potion (that uses flask-sqlalchemy) committing the current transaction when models are created/updated/removed. The previous code is committing because of the default parameter commit, e.g create(self, properties, commit=True).
At this point we could simply set commit=False and we would flush the session which keeps the current transactional concept, except if the operation fails (in this case the transaction is rollbacked).
In addition, #2028 rollbacks the transaction in Potion's exception handler.
If I understand correctly, the only reason to add a savepoint (session.begin_nested()) is for our tests as we do not want to rollback the data preparation step.
We can have different failure scenarios (where the transaction has to be handled correctly):
- the model cannot be created because a validation steps fails (e.g try to create a HarvestRecord)
- database operations fail during a
flush
The flow diagrams are:
- Production: Model Validation Error
- Open a transaction
S0 - We try to create a model, e.g
HarvestRecord, but aModelValidationErroris raised - Potion
_exception_handler()catches this exception and issues aRollback, back toS0
- Open a transaction
- Production: Persistence error
- Open a transaction (
S0) - We create a model, a
savepointis created within the transaction (S1) session.flush()fails, the transaction is rolled back, we are back toS1and an exception is raised- Potion
_exception_handler()catches theflushexception and issues aRollback, back toS0
- Open a transaction (
For the tests, I am unsure what exactly happens. Right now I do not see why begin_nested is needed.
|
I got into it. I would need an explanation on why |
|
In addition do you know what the logic of |
|
50mn of brainstorming concluded this is good to go. Thanks @nemmis |
It should be framework decision, not lib decision