Skip to content
This repository was archived by the owner on Oct 9, 2023. It is now read-only.

Commit a76af4e

Browse files
Close Transactions Properly (#45)
## What is the goal of this PR? Properly close transactions that was leading to failing client-python tests, and ensure that tests that are failing clean up properly rather than exiting without closing transactions. ## What are the changes implemented in this PR? * Exhaust the gRPC iterator when the transaction is closed to ensure that `onCompleted()` is called on the server. Previously, we were emptying the input iterator and adding `None` to its queue, but this was not being consumed. Thus, the transactions was not being cleaned up on the server as the `transaction(stream)` RPC call was never completed cleanly. * Utilise `addCleanup` to close transactions even if the tests fail - this is always executed regardless of test status. Closes #44
1 parent 4410db0 commit a76af4e

File tree

3 files changed

+25
-13
lines changed

3 files changed

+25
-13
lines changed

grakn/service/Session/TransactionService.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ def send(self, request):
155155
self._add_request(request)
156156
response = next(self._response_iterator)
157157
except Exception as e: # specialize into different gRPC exceptions?
158-
# on any GRPC exception, close the stream
159-
self.close()
158+
# invalidate this communicator, functionally this occurs automatically on exception (iterator not usable anymore)
159+
self._closed = True
160160
raise GraknError("Server/network error: {0}\n\n generated from request: {1}".format(e, request))
161161

162162
if response is None:
@@ -165,7 +165,13 @@ def send(self, request):
165165
return response
166166

167167
def close(self):
168-
with self._queue.mutex: # probably don't even need the mutex
169-
self._queue.queue.clear()
170-
self._queue.put(None)
171-
self._closed = True
168+
if not self._closed:
169+
with self._queue.mutex: # probably don't even need the mutex
170+
self._queue.queue.clear()
171+
self._queue.put(None)
172+
self._closed = True
173+
# force exhaust the iterator so `onCompleted()` is called on the server
174+
try:
175+
next(self._response_iterator)
176+
except StopIteration:
177+
pass

tests/integration/test_concept.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,11 @@ def tearDownClass(cls):
7777
def setUp(self):
7878
global session
7979
self.tx = session.transaction().write()
80+
# functions called by `addCleanup` are reliably called independent of test pass or failure
81+
self.addCleanup(self.cleanupTransaction, self.tx)
8082

81-
def tearDown(self):
82-
self.tx.close()
83-
83+
def cleanupTransaction(self, tx):
84+
tx.close()
8485

8586

8687
class test_Concept(test_concept_Base):
@@ -111,10 +112,12 @@ def test_re_delete_instance(self):
111112
none_car = self.tx.get_concept(car.id)
112113
self.assertIsNone(none_car)
113114

114-
with self.assertRaises(GraknError):
115+
with self.assertRaises(GraknError) as context:
115116
car.delete()
116117

117-
118+
self.assertTrue("FAILED_PRECONDITION" in str(context.exception))
119+
120+
118121
def test_is_each_schema_type(self):
119122
car_type = self.tx.put_entity_type("car")
120123
car = car_type.create()

tests/integration/test_grakn.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,13 @@ def tearDownClass(cls):
161161
client.close()
162162

163163
def setUp(self):
164+
global session
164165
self.tx = session.transaction().write()
166+
# functions called by `addCleanup` are reliably called independent of test pass or failure
167+
self.addCleanup(self.cleanupTransaction, self.tx)
165168

166-
def tearDown(self):
167-
self.tx.close()
169+
def cleanupTransaction(self, tx):
170+
tx.close()
168171

169172

170173

0 commit comments

Comments
 (0)