Embedding pipeline mechanics: broker safety, chunking, dispatch - #3645
Open
mbertrand wants to merge 3 commits into
Open
Embedding pipeline mechanics: broker safety, chunking, dispatch#3645mbertrand wants to merge 3 commits into
mbertrand wants to merge 3 commits into
Conversation
OpenAPI ChangesNo changes detected Unexpected changes? Ensure your branch is up-to-date with |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adjusts the Celery/Qdrant embedding pipeline’s dispatch mechanics to reduce broker amplification during backlogs, improve batching behavior, and make embedding execution more operationally tunable—without changing which resources/content files are embedded.
Changes:
- Increased broker safety by configuring a longer broker
visibility_timeout, and madegenerate_embeddingsrate limiting configurable via settings. - Reduced broker/result-backend load by making embedding tasks fire-and-forget (
ignore_result=True) and removing the prior “finalize” tail/counter plumbing. - Improved embedding efficiency by batching Qdrant point retrievals and skipping some redundant payload writes; updated related tests accordingly.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| main/settings.py | Updates embedding chunk-size defaults and introduces a dedicated content-file chunk size setting. |
| main/settings_celery.py | Adds broker visibility_timeout transport options and makes embedding task rate-limit configurable. |
| vector_search/tasks.py | Refactors embedding task dispatch patterns (groups vs chains), adds ignore_result on embedding tasks, filters run embedding to published files. |
| vector_search/utils.py | Adds batched Qdrant retrieve helper and uses retrieved points to reduce per-document Qdrant calls and some payload writes. |
| learning_resources_search/plugins.py | Switches to publish-time retry on task dispatch via apply_async(retry=..., retry_policy=...). |
| vector_search/tasks_test.py | Updates expectations for new dispatch semantics and removal of finalize/counter behavior. |
| vector_search/utils_test.py | Adds coverage for batched retrieval and payload-write skipping behavior. |
mbertrand
force-pushed
the
mb/embed-mechanics
branch
from
July 28, 2026 13:36
0ac5af2 to
ad1ac5b
Compare
Phase 1 (mechanics) of the content-file embedding load reduction: - Raise Redis broker visibility_timeout to 6h so long-running summarization+embed tasks are not redelivered mid-flight during a backlog (the primary redelivery-storm driver). - Split QDRANT_CHUNK_SIZE (10->100 for resources) from a new QDRANT_CONTENT_FILE_CHUNK_SIZE (25) so content-file tasks stay small. - ignore_result on fire-and-forget embedding tasks; drop the finalize_embeddings tail and embed_errors counter plumbing (failure signal is log.exception + the weekly presence-based healthcheck). - Convert whole-catalog backfill from self.replace(chain) to bounded apply_async batches; per-run dispatch becomes a group of chunk sigs (no O(N^2) chain payloads). - embed_run_content_files filters to published files. - generate_embeddings rate_limit from CELERY_EMBEDDINGS_RATE_LIMIT. - try_with_retry_as_task dispatches via apply_async with publish-time retry_policy instead of re-.delay() on any exception. Addresses mitodl/hq#12453 Related: mitodl/hq#12015 (infra concurrency/grace-period counterpart), mitodl/hq#12008 (Qdrant performance settings), mitodl/hq#12172 (embedding pipeline failures). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers the published-only filter returning None (no group), per review feedback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Reorder the content_files_loaded chain to purge unpublished files' points before embedding (cherry-picked from the change-detection follow-up). celery uplifts a group replacement to a chord, so with embed first the purge task becomes the chord body; if the gap between two chunk completions exceeds result_expires (1h) the chord's Redis bookkeeping expires and the body is dropped with no error logged. Purging first makes the body a bare celery.accumulate, whose loss costs nothing. The two tasks touch disjoint sets (published=False vs published=True). - Drop the payload-equality write-skip in update_learning_resource_payload. It never fired: Qdrant returns resource_age_date as a string while the serialized doc holds a datetime, so the payloads never compared equal. Its test asserted against a MagicMock echoing its own input, so the no-op looked covered. The batched retrieve it rode on is unaffected and still saves N retrieves per sweep. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mbertrand
force-pushed
the
mb/embed-mechanics
branch
from
July 28, 2026 18:50
ad1ac5b to
f4050e9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What are the relevant tickets?
Addresses mitodl/hq#12453. Related: mitodl/hq#12015 (infra concurrency cap + grace period), mitodl/hq#12008 (Qdrant performance settings), mitodl/hq#12172 (embedding pipeline failures).
Description (What does it do?)
Phase 1 of the content-file embedding load reduction — task/broker mechanics that amplify legitimate work into storms. No change to what gets embedded.
visibility_timeout→ 6h (CELERY_BROKER_TRANSPORT_OPTIONS). The default 3600s is shorter than a long summarize+embed task, so in-flight tasks were redelivered en masse during backlogs (the redelivery-storm driver).QDRANT_CHUNK_SIZE10→100 (resources, cheap per item); newQDRANT_CONTENT_FILE_CHUNK_SIZE=25(content files do inline summarization, kept small).ignore_result=Trueon fire-and-forget embedding tasks; drop thefinalize_embeddingstail and theembed_errorscounter plumbing. Failure signal is nowlog.exceptioningenerate_embeddingsplus the weekly presence-basedembeddings_healthcheck.start_embed_resources/embed_learning_resources_by_idgo fromself.replace(chain(...))over the whole catalog (O(N²) message bytes) to a loop ofapply_asyncbatches. Per-run dispatch becomes agroupof chunk signatures.embed_run_content_filesfilters to published files — stop embedding files the very next chained task deletes.generate_embeddings.rate_limitfrom a newCELERY_EMBEDDINGS_RATE_LIMITsetting (same 200/m default) so ops can tune without a deploy.try_with_retry_as_taskdispatches viaapply_async(retry=True, retry_policy=…)instead of re-.delay()on any exception (which could double-publish during a broker hiccup).vector_search/utils.py.How can this be tested?
21600 100 25 200/m.ignore_result— a dispatched embedding task stores no result key:docker compose exec -T redis redis-cli EXISTS celery-task-meta-<id>→0.embed_run_content_filesembeds only the published files, dispatched as agroupof ⌈published/25⌉ chunks, points land in Qdrant with no redelivered-task warnings.docker compose run --rm web uv run pytest vector_search/tasks_test.py vector_search/utils_test.py learning_resources_search/plugins_test.py— all pass.Additional Context
Ops note before merge: confirm the prod env doesn't pin
QDRANT_CHUNK_SIZEin ol-infrastructure — its default is what changes here. This is the app-side complement to the infra-side fixes in mitodl/hq#12015.