Skip to content
This repository was archived by the owner on Mar 31, 2026. It is now read-only.

Commit 6c16079

Browse files
authored
fix(experimental): implement requests_done method to signal end of requests in async streams. Gracefully close streams. (#1700)
fix(experimental): implement requests_done method to signal end of requests in async streams. Gracefully close streams.
1 parent 16cf512 commit 6c16079

4 files changed

Lines changed: 64 additions & 0 deletions

File tree

‎google/cloud/storage/_experimental/asyncio/async_read_object_stream.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,16 @@ async def close(self) -> None:
151151
"""Closes the bidi-gRPC connection."""
152152
ifnotself._is_stream_open:
153153
raiseValueError("Stream is not open")
154+
awaitself.requests_done()
154155
awaitself.socket_like_rpc.close()
155156
self._is_stream_open=False
156157

158+
asyncdefrequests_done(self):
159+
"""Signals that all requests have been sent."""
160+
161+
awaitself.socket_like_rpc.send(None)
162+
awaitself.socket_like_rpc.recv()
163+
157164
asyncdefsend(
158165
self, bidi_read_object_request: _storage_v2.BidiReadObjectRequest
159166
) ->None:

‎google/cloud/storage/_experimental/asyncio/async_write_object_stream.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,16 @@ async def close(self) -> None:
152152
"""Closes the bidi-gRPC connection."""
153153
ifnotself._is_stream_open:
154154
raiseValueError("Stream is not open")
155+
awaitself.requests_done()
155156
awaitself.socket_like_rpc.close()
156157
self._is_stream_open=False
157158

159+
asyncdefrequests_done(self):
160+
"""Signals that all requests have been sent."""
161+
162+
awaitself.socket_like_rpc.send(None)
163+
awaitself.socket_like_rpc.recv()
164+
158165
asyncdefsend(
159166
self, bidi_write_object_request: _storage_v2.BidiWriteObjectRequest
160167
) ->None:
@@ -186,3 +193,4 @@ async def recv(self) -> _storage_v2.BidiWriteObjectResponse:
186193
@property
187194
defis_stream_open(self) ->bool:
188195
returnself._is_stream_open
196+

‎tests/unit/asyncio/test_async_read_object_stream.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,41 @@ async def test_close(mock_client, mock_cls_async_bidi_rpc):
197197
read_obj_stream=awaitinstantiate_read_obj_stream(
198198
mock_client, mock_cls_async_bidi_rpc, open=True
199199
)
200+
read_obj_stream.requests_done=AsyncMock()
200201

201202
# act
202203
awaitread_obj_stream.close()
203204

204205
# assert
206+
read_obj_stream.requests_done.assert_called_once()
205207
read_obj_stream.socket_like_rpc.close.assert_called_once()
206208
assertnotread_obj_stream.is_stream_open
207209

208210

211+
@mock.patch(
212+
"google.cloud.storage._experimental.asyncio.async_read_object_stream.AsyncBidiRpc"
213+
)
214+
@mock.patch(
215+
"google.cloud.storage._experimental.asyncio.async_grpc_client.AsyncGrpcClient.grpc_client"
216+
)
217+
@pytest.mark.asyncio
218+
asyncdeftest_requests_done(mock_client, mock_cls_async_bidi_rpc):
219+
"""Test that requests_done signals the end of requests."""
220+
# Arrange
221+
read_obj_stream=awaitinstantiate_read_obj_stream(
222+
mock_client, mock_cls_async_bidi_rpc, open=True
223+
)
224+
read_obj_stream.socket_like_rpc.send=AsyncMock()
225+
read_obj_stream.socket_like_rpc.recv=AsyncMock()
226+
227+
# Act
228+
awaitread_obj_stream.requests_done()
229+
230+
# Assert
231+
read_obj_stream.socket_like_rpc.send.assert_called_once_with(None)
232+
read_obj_stream.socket_like_rpc.recv.assert_called_once()
233+
234+
209235
@mock.patch(
210236
"google.cloud.storage._experimental.asyncio.async_read_object_stream.AsyncBidiRpc"
211237
)

‎tests/unit/asyncio/test_async_write_object_stream.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,13 @@ async def test_close(mock_cls_async_bidi_rpc, mock_client):
289289
write_obj_stream=awaitinstantiate_write_obj_stream(
290290
mock_client, mock_cls_async_bidi_rpc, open=True
291291
)
292+
write_obj_stream.requests_done=AsyncMock()
292293

293294
# Act
294295
awaitwrite_obj_stream.close()
295296

296297
# Assert
298+
write_obj_stream.requests_done.assert_called_once()
297299
write_obj_stream.socket_like_rpc.close.assert_called_once()
298300
assertnotwrite_obj_stream.is_stream_open
299301

@@ -394,3 +396,24 @@ async def test_recv_without_open_should_raise_error(
394396
# Act & Assert
395397
withpytest.raises(ValueError, match="Stream is not open"):
396398
awaitwrite_obj_stream.recv()
399+
400+
401+
@pytest.mark.asyncio
402+
@mock.patch(
403+
"google.cloud.storage._experimental.asyncio.async_write_object_stream.AsyncBidiRpc"
404+
)
405+
asyncdeftest_requests_done(mock_cls_async_bidi_rpc, mock_client):
406+
"""Test that requests_done signals the end of requests."""
407+
# Arrange
408+
write_obj_stream=awaitinstantiate_write_obj_stream(
409+
mock_client, mock_cls_async_bidi_rpc, open=True
410+
)
411+
write_obj_stream.socket_like_rpc.send=AsyncMock()
412+
write_obj_stream.socket_like_rpc.recv=AsyncMock()
413+
414+
# Act
415+
awaitwrite_obj_stream.requests_done()
416+
417+
# Assert
418+
write_obj_stream.socket_like_rpc.send.assert_called_once_with(None)
419+
write_obj_stream.socket_like_rpc.recv.assert_called_once()

0 commit comments

Comments
 (0)