qdrant / qdrant/fastembed

[Bug]: Closing a parallel result iterator early hangs while joining workers

Open
#669 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
3.2k
Forks
248
Avg merge
4d 8h
Merged PRs (30d)
4

Description

What happened?

Parallel embedding uses ParallelWorkerPool.ordered_map(), which returns a generator backed by worker processes. If a caller consumes only a prefix of the results and then closes the iterator, close() never returns and a worker process is left blocked.

The same cleanup path is reached if iteration is interrupted by an exception. semi_ordered_map() sends stop signals only after the input stream is exhausted, but its finally block always calls join(). On early generator exit, workers are still waiting on the input queue, so the parent waits indefinitely.

What is the expected behaviour?

Closing or abandoning a partially consumed parallel result iterator should promptly stop its workers and release the multiprocessing queues. Fully consumed iterators should keep the normal graceful join path.

A minimal reproducible example
from fastembed.parallel_processor import ParallelWorkerPool, Worker


class EchoWorker(Worker):
    @classmethod
    def start(cls, **kwargs):
        return cls()

    def process(self, items):
        yield from items


pool = ParallelWorkerPool(1, EchoWorker, start_method="fork")
results = pool.ordered_map(range(1000))
assert next(results) == 0
results.close()  # hangs indefinitely on ParallelWorkerPool.join()
What Python version are you on? e.g. python --version

Python 3.11.15, installed with uv

FastEmbed version

Current main at 685fd9b (0.8.0)

What os are you seeing the problem on?

MacOS

Relevant stack traces and/or logs

There is no exception. The main process blocks in ParallelWorkerPool.join() while the worker remains blocked in input_queue.get().

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in fastembed.parallel_processor at ParallelWorkerPool.ordered_map(), semi_ordered_map(), and join(), then run the provided EchoWorker reproducer on Python 3.11. Verify that closing or abandoning a partially consumed iterator stops workers and releases queues promptly, while fully consumed iterators still use the graceful join path.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
distributed-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.