Skip to content

Replace ThreadPool with ThreadPoolExecutor for async_req#633

Open
yonatan-genai wants to merge 3 commits intopinecone-io:mainfrom
yonatan-genai:fix/replace-threadpool-with-executor
Open

Replace ThreadPool with ThreadPoolExecutor for async_req#633
yonatan-genai wants to merge 3 commits intopinecone-io:mainfrom
yonatan-genai:fix/replace-threadpool-with-executor

Conversation

@yonatan-genai
Copy link
Copy Markdown

@yonatan-genai yonatan-genai commented Apr 3, 2026

Summary

The async_req=True code path uses multiprocessing.pool.ThreadPool, which
depends on POSIX named semaphores (sem_open). This fails on platforms without
/dev/shm, notably AWS Lambda, Android, and Docker containers with restricted
shared memory.

ThreadPool is only used for thread-based parallelism here, not multiprocessing.
The ThreadPoolExecutor (from concurrent.futures) is already used internally
by the async_threadpool_executor path. This change reuses it for async_req
as well, eliminating the multiprocessing dependency entirely.

A .get() alias is added to the returned Future for backward compatibility
with existing code that calls .get(timeout) (the ApplyResult API) instead
of .result(timeout) (the Future API).

Changes

  • pinecone/openapi_support/api_client.py: Replace self.pool.apply_async()
    with self.threadpool_executor.submit(), remove ThreadPool property and
    multiprocessing imports
  • pinecone/adapters/response_adapters.py: Update UpsertResponseTransformer
    from ApplyResult to Future

Related


Note

Medium Risk
Touches core async request plumbing by swapping ThreadPool.apply_async() for ThreadPoolExecutor.submit() and emulating the old .get() API; regressions could surface in timeouts, cancellation, or code that relied on ApplyResult semantics.

Overview
Replaces the async_req=True execution path to use concurrent.futures.ThreadPoolExecutor instead of multiprocessing.pool.ThreadPool, removing the multiprocessing/POSIX semaphore dependency and improving compatibility with restricted runtimes (e.g., Lambda/containers without /dev/shm).

Updates async return types accordingly: ApiClient.call_api() now returns a Future with a backward-compatible .get() alias, and UpsertResponseTransformer now wraps a Future and provides both get() and result() to return the transformed SDK UpsertResponse.

Reviewed by Cursor Bugbot for commit ce21f28. Bugbot is set up for automated code reviews on this repo. Configure here.

…sync_req

ThreadPool depends on POSIX named semaphores (sem_open), which fails on
platforms without /dev/shm such as AWS Lambda. The async_req code path
only needs thread-based parallelism, not multiprocessing.

This reuses the existing threadpool_executor property (already used by
the async_threadpool_executor path) for async_req as well. A .get()
alias is added to the returned Future for backward compatibility with
code that calls .get() instead of .result().

Removes the multiprocessing dependency from the client entirely.

<claude>
Comment thread pinecone/adapters/response_adapters.py Outdated
The .get() alias is monkey-patched onto Future for external backward
compat. Internal code should call .result() directly.
@yonatan-genai
Copy link
Copy Markdown
Author

Fixed in 1c55cc9 — internal code now calls .result() directly instead of relying on the external .get() alias.

This PR also fixes the root cause of #257.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1c55cc9. Configure here.

Comment thread pinecone/adapters/response_adapters.py
Future.result() would leak through __getattr__ and return the raw
OpenAPI response without adapting it. Since the PR exposes a dual
.get()/.result() API on futures, users may try .result() on the
transformer too — it should return the transformed UpsertResponse.
@yonatan-genai
Copy link
Copy Markdown
Author

Fixed in ce21f28 — added an explicit .result() method on the transformer that returns the adapted UpsertResponse, so both .get() and .result() on the transformer now go through adapt_upsert_response instead of leaking the raw OpenAPI response via __getattr__.

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.

1 participant