Repository navigation
fix(segments): schedule index change before persisting segment status - #45244
TINGyu123644 wants to merge 1 commit into
Conversation
change_segment_status committed the enabled/disabled state before publishing the enable/disable Celery task. When the broker is unavailable the publish raises after the commit, so the persisted state already matches the request and a retry is skipped as a no-op: the API returns success but the segment is never restored to (or removed from) the index. Schedule the index side effect first and persist the desired state afterwards. The enable/disable tasks select segments by id (status COMPLETED) and are idempotent loads/removals, so they do not depend on the committed enabled value. With this ordering a failed publish leaves nothing committed, and an explicit retry re-dispatches. Fixes langgenius#45238
GYJ99
left a comment
There was a problem hiding this comment.
I see the intended fix for the broker-publication failure case, but moving _index.change_status() before _store.set_segments() appears to introduce the reverse partial-failure window: if the task is published successfully and the DB write then fails (e.g. transient DB error/deadlock), Celery may already remove or add the index while the persisted enabled state remains unchanged. For example, a failed disable request could leave a segment marked enabled in the DB but absent from the retrieval index. The new tests cover dispatch failure and call ordering, but not persistence failure after a successful dispatch.
Could we cover that failure path or avoid the ordering change? The explicit retry/reconciliation approach in #45239 seems worth comparing, since it keeps the existing persist-then-dispatch sequence and repairs retries even when status already matches. This is a code-path concern, not a claim of having reproduced the race in a live Celery environment.
Fixes #45238
Summary
change_segment_statusin the Console segment-status API committed theenabled/disabled_at/disabled_byfields before publishing the enable/disable Celery task. When the broker is unavailable, the publish raises after the commit, so the persisted state already matches the request. A retry is then skipped as a no-op (segment.enabled == (action == "enable")), the API returns success, and the segment is never restored to (or removed from) the index - the exact sequence reported in the issue.This orders the operation the other way: schedule the index side effect first, persist the desired state afterwards.
status == COMPLETED) and perform idempotent index loads/removals, so they do not depend on the committedenabledvalue; dispatch-before-commit is therefore safe.Testing
api/tests/unit_tests/services/knowledge/segments/test_application.py:test_status_change_does_not_persist_state_when_dispatch_fails- dispatch raises, nothing is persisted (store.set_segmentsnever called), and the error is translated toSegmentStatusUpdateError.test_status_change_dispatches_index_change_before_persisting_state- ordering assertion (dispatch before persist) plus persisted values check.ruff checkandruff format --check(repo.ruff.toml: line-length 120) are clean for both touched files.AI disclosure
This change was produced with AI assistance (Claude, via an automated contribution workflow) and reviewed by the account owner.