Repository navigation
♻️ Refactor(data-process): replace Ray with Celery prefork - #3888
Merged
Merged
Conversation
Run parsing in process-local Celery prefork children, keep orchestration and forwarding on thread workers, and remove the Ray runtime, dependency, and deployment surface. Co-authored-by: Codex <noreply@openai.com> Generated-by: gpt-5-codex
# Conflicts: # backend/data_process/app.py # backend/data_process/tasks.py # backend/data_process_service.py # doc/docs/en/backend/overview.md # doc/docs/en/developer-guide/overview.md # doc/docs/zh/backend/overview.md # doc/docs/zh/developer-guide/overview.md # test/backend/data_process/test_tasks.py # test/backend/test_data_process_service_entrypoint.py
cj2026-bit
requested review from
Dallas98,
WMC001 and
jeffwu-1999
as code owners
September 8, 2026 09:25
This reverts commit 9aa8d45.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
…-celery-prefork # Conflicts: # deploy/env/.env.example # frontend/public/locales/en/common.json # frontend/public/locales/zh/common.json
Keep the synchronous parse entry point reachable through the tasks module so coverage and isolation tests can patch one import site. Use a redundant-alias re-export to satisfy F401.
Problem: the stub_modules fixture in test_data_process_app.py assigned stub modules directly to sys.modules without restoring them, so the stubs leaked into every later test file sharing the same pytest process. Running test_data_process_app.py before test_data_process_service.py failed all 52 service tests in setUp with AttributeError: '_CeleryAppStub' object has no attribute 'reset_mock'. The leak was invisible to CI because run_all_test.py runs each test file in its own subprocess. Fix: replace the six direct sys.modules assignments with monkeypatch.setitem so the real modules are restored when the fixture tears down. Behavior during each test is unchanged. Verification: - pytest test/backend/app/test_data_process_app.py test/backend/services/test_data_process_service.py -> 76 passed (was 24 passed / 52 failed) - each file alone: 24 passed / 52 passed (no regression) - wider combo (app + services + tasks + worker + coverage): app+services now pass together; the remaining failures are a pre-existing module-level mock leak in test_data_process_service.py that exists on develop and is out of scope here.
cj2026-bit
force-pushed
the
codex/data-process-celery-prefork
branch
from
September 24, 2026 08:20
083dfca to
5a9718a
Compare
cj2026-bit
force-pushed
the
codex/data-process-celery-prefork
branch
from
September 24, 2026 08:31
5a9718a to
53024c4
Compare
…-celery-prefork # Conflicts: # NOTICE
jeffwu-1999
reviewed
Oct 8, 2026
jeffwu-1999
approved these changes
Oct 8, 2026
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.
Problem
The data-process parsing stage ran on a Ray cluster. Ray brings a large resident footprint (actor pool + cluster system processes), keeps its actor pool alive permanently, and pulls the full data-process import stack into every Celery worker process. This PR removes Ray entirely and moves the parsing stage to a Celery prefork pool.
Solution
preforkpool (--autoscale=DP_PARSE_MAX_PROCESSES,DP_PARSE_MIN_PROCESSES,--max-tasks-per-child=DP_PARSE_MAX_TASKS_PER_CHILD); forwarding, aggregation and ES ingestion keep using the existing Celery thread pools.sdk/nexent/data_process/model_registry.py): parser children preloadDP_PRELOAD_MODELS(defaultunstructured_default) at child init and reuse the loaded models across tasks; other models (e.g.table_transformer) load on demand.backend/consts/const.py:DP_PARSE_MAX_PROCESSES=3,DP_PARSE_MIN_PROCESSES=1,DP_PARSE_THREADS_PER_PROCESS=2,DP_PARSE_MAX_TASKS_PER_CHILD=1000,DP_PRELOAD_MODELS=unstructured_default,DP_PARSER_STARTUP_TIMEOUT_S=300.ray_init_failederror code) with no fallback switch.Verification
CI
All 17 checks green on the pushed head (including the
testjob with the full backend pytest suite +coverage.xml+ Codecov upload,codecov/patch,build-data-processamd64/arm64 image builds, frontendtype-check, CodeQL and SonarCloud).Live benchmark: Celery prefork (this PR) vs Ray (develop)
Same machine, same ES knowledge-base stack (Docker PG/Redis/ES/MinIO/Supabase + WSL backends), same driver script and assets: three
4.95 MiBGBK TXT files (2237chunks each, the same file used in the design benchmark), full API flow (sign-in -> create KB -> upload ->/file/process-> poll to terminal state). Prefork runs with default config (min=1 / max=3,unstructured_defaultpreloaded). Host: 16 CPU / 20 GiB WSL2.1. Idle baseline (no tasks)
Ray workers are ~1 GiB each because
ray_actors.pyimportsnexent.data_process.DataProcessCoreat module level, which pulls the torch/unstructured stack into every Celery worker; this PR moves the heavy imports into the parser children (launchers stay at ~183 MiB). Idle numbers reproduced across 3 independent starts on each side.2. Full ingestion flow (3 x 4.95 MiB TXT)
Throughput and CPU are equivalent within noise; the embedding API is the flow bottleneck on both sides (~390-400 s of forwarding).
3. Model cold start
unstructured_default1.95 s /table_transformer3.83 s4. Recycling and scale-up
AUTOSCALE_KEEPALIVE) have passed since the last scale-up and the pool is idle; shrinks stepwise to min=1