Skip to content

fix(azure-storage): close ContainerClient in sync lazy_load - #832

Merged
anjaliratnam-msft merged 3 commits into
langchain-ai:mainfrom
0xDevNinja:fix/azure-storage-close-container-client
Jul 22, 2026
Merged

fix(azure-storage): close ContainerClient in sync lazy_load#832
anjaliratnam-msft merged 3 commits into
langchain-ai:mainfrom
0xDevNinja:fix/azure-storage-close-container-client

Conversation

@0xDevNinja

Copy link
Copy Markdown
Contributor

Description

AzureBlobStorageLoader.lazy_load (sync) constructs a ContainerClient but never closes it:

container_client = ContainerClient(**self._get_client_kwargs(credential))
for blob_name in self._yield_blob_names(container_client):
    ...

The ContainerClient owns an HTTP transport / connection pool, so every call to lazy_load (i.e. every load()) leaks those connections until GC. The async counterpart already scopes its client correctly with async with async_container_client: — only the sync path is missing the cleanup.

Fix

Use the client as a context manager so it is closed once iteration finishes, mirroring alazy_load:

with ContainerClient(**self._get_client_kwargs(credential)) as container_client:
    for blob_name in self._yield_blob_names(container_client):
        ...

ContainerClient supports the context-manager protocol and returns itself from __enter__, so behavior is unchanged aside from the client now being closed.

Testing

Added test_lazy_load_closes_container_client, which asserts the client is exited after a full lazy_load. The two sync container-client mock fixtures now set __enter__.return_value = mock_client so the mock matches the real client (which returns self from __enter__); all existing sync load tests continue to exercise the same object. Verified the new test fails without the fix and passes with it. make lint (ruff + ruff format + mypy over package and tests) is clean; full unit suite passes.

`lazy_load` created a `ContainerClient` but never closed it, leaking the
underlying HTTP transport / connection pool for every load. The async
counterpart `alazy_load` already scopes its client with `async with`; mirror
that on the sync path by using the client as a context manager so it is
closed once iteration completes.

@anjaliratnam-msft anjaliratnam-msft left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for bringing up this issue! I think this looks good, I just had one small comment.

Comment on lines +212 to +223
def test_lazy_load_closes_container_client(
create_azure_blob_storage_loader: Callable[..., AzureBlobStorageLoader],
mock_container_client: Tuple[MagicMock, MagicMock],
) -> None:
"""The sync container client must be closed once iteration completes,
mirroring the ``async with`` used in ``alazy_load``."""
_, mock_client = mock_container_client
loader = create_azure_blob_storage_loader()
list(loader.lazy_load())
mock_client.__exit__.assert_called_once()


Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding a new test for this, I think we can just add that assertion in test_lazy_load to help minimize the code changes.

Address review feedback: fold the container-client close assertion into
`test_lazy_load` instead of adding a separate test, keeping the change
minimal.
@0xDevNinja

Copy link
Copy Markdown
Contributor Author

Makes sense — folded the assertion into test_lazy_load and dropped the separate test in 5102235. Confirmed it still catches the regression: with the with removed from lazy_load, test_lazy_load fails on the __exit__ assertion.

The only other test change left is the two sync fixtures setting mock_client.__enter__.return_value = mock_client, which is needed so the mock matches the real ContainerClient (it returns self from __enter__).

@anjaliratnam-msft anjaliratnam-msft left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@anjaliratnam-msft
anjaliratnam-msft merged commit 900d5e3 into langchain-ai:main Jul 22, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants