@@ -353,6 +353,46 @@ def test_insert_multiple_ts_single_call__above_dps_limit_below_ts_limit(
353353 cognite_client .time_series .data .insert_multiple (dps_objects )
354354 assert 2 == len (mock_post_datapoints .get_requests ())
355355
356+ def test_insert_multiple_dump_only_called_within_semaphore (
357+ self ,
358+ cognite_client : CogniteClient ,
359+ mock_post_datapoints : HTTPXMock ,
360+ monkeypatch : MonkeyPatch ,
361+ async_client : AsyncCogniteClient ,
362+ ) -> None :
363+ # Bug in 8.0.0 to 8.1.0: all asyncio tasks were created at once and dp.dump() (synchronous,
364+ # no await) ran in every task before any of them reached the semaphore, causing all payloads
365+ # to be materialised in memory simultaneously (memory regression vs v7).
366+ sem_held = False
367+ dump_sem_held : list [bool ] = []
368+
369+ class _MockSemaphore :
370+ async def __aenter__ (self ) -> _MockSemaphore :
371+ nonlocal sem_held
372+ sem_held = True
373+ return self
374+
375+ async def __aexit__ (self , * _ : Any ) -> None :
376+ nonlocal sem_held
377+ sem_held = False
378+
379+ monkeypatch .setattr (async_client .time_series .data , "_get_semaphore" , lambda _op : _MockSemaphore ())
380+
381+ original_dump = _InsertDatapoint .dump
382+
383+ def tracking_dump (self : _InsertDatapoint ) -> dict :
384+ dump_sem_held .append (sem_held )
385+ return original_dump (self )
386+
387+ monkeypatch .setattr (_InsertDatapoint , "dump" , tracking_dump )
388+
389+ monkeypatch .setattr (async_client .time_series .data , "_DPS_INSERT_LIMIT" , 5 )
390+ dps = [(i * 1e11 , i ) for i in range (50 )]
391+ cognite_client .time_series .data .insert (dps , id = 1 )
392+
393+ assert len (dump_sem_held ) == 50
394+ assert all (dump_sem_held ), "dp.dump() was called outside the semaphore context"
395+
356396
357397@pytest .fixture
358398def mock_delete_datapoints (
0 commit comments