Replace ThreadPool with ThreadPoolExecutor for async_req#633
Replace ThreadPool with ThreadPoolExecutor for async_req#633yonatan-genai wants to merge 1 commit intopinecone-io:mainfrom
Conversation
…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>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| The SDK UpsertResponse dataclass. | ||
| """ | ||
| openapi_response = self._apply_result.get(timeout) | ||
| openapi_response = self._future.get(timeout) |
There was a problem hiding this comment.
Future has no .get() method; use .result()
Medium Severity
UpsertResponseTransformer.get() calls self._future.get(timeout), but concurrent.futures.Future does not have a .get() method — its API is .result(timeout). This only works by accident because api_client.py monkey-patches future.get = future.result on the returned future. The internal UpsertResponseTransformer class should call self._future.result(timeout) directly instead of relying on the external monkey-patch, which is intended for backward compatibility of external callers.


Summary
The
async_req=Truecode path usesmultiprocessing.pool.ThreadPool, whichdepends on POSIX named semaphores (
sem_open). This fails on platforms without/dev/shm, notably AWS Lambda, Android, and Docker containers with restrictedshared memory.
ThreadPoolis only used for thread-based parallelism here, not multiprocessing.The
ThreadPoolExecutor(fromconcurrent.futures) is already used internallyby the
async_threadpool_executorpath. This change reuses it forasync_reqas well, eliminating the
multiprocessingdependency entirely.A
.get()alias is added to the returnedFuturefor backward compatibilitywith existing code that calls
.get(timeout)(theApplyResultAPI) insteadof
.result(timeout)(theFutureAPI).Changes
pinecone/openapi_support/api_client.py: Replaceself.pool.apply_async()with
self.threadpool_executor.submit(), remove ThreadPool property andmultiprocessing imports
pinecone/adapters/response_adapters.py: UpdateUpsertResponseTransformerfrom
ApplyResulttoFutureRelated
Note
Medium Risk
Touches the async request execution path and changes the concrete return type for
async_req=True; subtle behavior differences betweenApplyResult.get()andFuture.result()(timeouts/cancellation/exceptions) could affect callers despite the.getcompatibility alias.Overview
Async OpenAPI requests (
async_req=True) are migrated offmultiprocessing.pool.ThreadPooltoconcurrent.futures.ThreadPoolExecutor, removing themultiprocessing/POSIX semaphore dependency and improving compatibility with restricted environments (e.g., Lambda containers).ApiClient.call_api()now returns aFuture(with a.getalias to.resultfor backward compatibility), andUpsertResponseTransformeris updated to wrap aFutureinstead of anApplyResultwhile keeping the same.get()-based transformation behavior.Written by Cursor Bugbot for commit 159cac6. This will update automatically on new commits. Configure here.