mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-19 14:11:04 +08:00
Feat: full optimization on connector dashboard (#14979)
### What problem does this PR solve? This PR improves the connector dashboard task management experience and adds better visibility into connector execution logs. ### Overview: #### Before <img width="700" alt="image" src="https://github.com/user-attachments/assets/e4a8ed6f-2e18-4f0f-8528-41a514550052" /> #### Now: <img width="700" alt="Screenshot from 2026-05-18 16-31-30" src="https://github.com/user-attachments/assets/d4ca193b-847a-49ae-9e4f-5fbca60ea627" /> ### 1. Add a new logging page to the connector dashboard A new logging page has been added so users can view connector task execution logs directly from the connector dashboard. ### 2. Merge the Resume button into Confirm The separate **Resume** button has been removed. The **Confirm** button now represents different actions depending on the current task state: - **Save**: Save form changes and reschedule tasks. - **Stop**: Cancel currently scheduled or running tasks. - **Resume**: Create new scheduled tasks after the previous tasks have been stopped. - **Start**: Start tasks when no task has been started yet. ### 3. Separate syncing and pruning tasks Connector tasks are now separated into **syncing** and **pruning**. Pruning is controlled by the **Sync deleted files** option: - When **Sync deleted files** is disabled, only syncing tasks are shown. - When **Sync deleted files** is enabled, both syncing and pruning tasks are shown. **Now: Sync deleted files disabled** <img width="700" alt="Sync deleted files disabled" src="https://github.com/user-attachments/assets/dbd9232e-614a-407f-a0b1-c109e5fa567d" /> **Now: Sync deleted files enabled** <img width="700" alt="Sync deleted files enabled" src="https://github.com/user-attachments/assets/1f527f48-ccb3-4ee8-97ca-086891489296" /> ### 4. Update logs in backend <img width="700" alt="image" src="https://github.com/user-attachments/assets/10a95a3f-98c1-4e67-8afa-ddf6cda5b0b2" /> ### 5. Remove connector resume API - Removed: `POST /v1/connectors/<connector_id>/resume` - Replaced by: `PATCH /v1/connectors/<connector_id>` ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@@ -133,7 +133,53 @@ def _patch_common_dependencies(monkeypatch):
|
||||
|
||||
@pytest.mark.anyio
|
||||
@pytest.mark.p2
|
||||
async def test_run_task_logic_cleans_up_for_empty_snapshot(monkeypatch):
|
||||
async def test_run_task_logic_skips_empty_sync_batches(monkeypatch):
|
||||
_patch_common_dependencies(monkeypatch)
|
||||
monkeypatch.setattr(
|
||||
sync_data_source.SyncLogsService,
|
||||
"increase_docs",
|
||||
lambda *_args, **_kwargs: pytest.fail("increase_docs should not be called for empty batches"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
sync_data_source.KnowledgebaseService,
|
||||
"get_by_id",
|
||||
lambda *_args, **_kwargs: pytest.fail("get_by_id should not be called for empty batches"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
sync_data_source.SyncLogsService,
|
||||
"duplicate_and_parse",
|
||||
lambda *_args, **_kwargs: pytest.fail("duplicate_and_parse should not be called for empty batches"),
|
||||
)
|
||||
|
||||
await _FakeSync(iter(([],)))._run_task_logic(_make_task())
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@pytest.mark.p2
|
||||
async def test_run_task_logic_skips_multiple_empty_sync_batches(monkeypatch):
|
||||
_patch_common_dependencies(monkeypatch)
|
||||
monkeypatch.setattr(
|
||||
sync_data_source.SyncLogsService,
|
||||
"increase_docs",
|
||||
lambda *_args, **_kwargs: pytest.fail("increase_docs should not be called for empty batches"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
sync_data_source.KnowledgebaseService,
|
||||
"get_by_id",
|
||||
lambda *_args, **_kwargs: pytest.fail("get_by_id should not be called for empty batches"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
sync_data_source.SyncLogsService,
|
||||
"duplicate_and_parse",
|
||||
lambda *_args, **_kwargs: pytest.fail("duplicate_and_parse should not be called for empty batches"),
|
||||
)
|
||||
|
||||
await _FakeSync(iter(([], [],)))._run_task_logic(_make_task())
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@pytest.mark.p2
|
||||
async def test_run_prune_task_logic_cleans_up_for_empty_snapshot(monkeypatch):
|
||||
cleanup_calls = []
|
||||
|
||||
_patch_common_dependencies(monkeypatch)
|
||||
@@ -148,7 +194,14 @@ async def test_run_task_logic_cleans_up_for_empty_snapshot(monkeypatch):
|
||||
_fake_cleanup,
|
||||
)
|
||||
|
||||
await _FakeSync((iter(()), []))._run_task_logic(_make_task())
|
||||
task = {**_make_task(), "task_type": sync_data_source.ConnectorTaskType.PRUNE}
|
||||
sync = _FakeSync(iter(()))
|
||||
sync.conf["sync_deleted_files"] = True
|
||||
sync.connector = types.SimpleNamespace(
|
||||
retrieve_all_slim_docs_perm_sync=lambda: iter(([],))
|
||||
)
|
||||
|
||||
await sync._run_task_logic(task)
|
||||
|
||||
assert cleanup_calls == [
|
||||
(
|
||||
@@ -166,7 +219,7 @@ async def test_run_task_logic_cleans_up_for_empty_snapshot(monkeypatch):
|
||||
|
||||
@pytest.mark.anyio
|
||||
@pytest.mark.p2
|
||||
async def test_run_task_logic_cleans_up_for_non_empty_snapshot(monkeypatch):
|
||||
async def test_run_prune_task_logic_cleans_up_for_non_empty_snapshot(monkeypatch):
|
||||
cleanup_calls = []
|
||||
|
||||
_patch_common_dependencies(monkeypatch)
|
||||
@@ -182,7 +235,14 @@ async def test_run_task_logic_cleans_up_for_non_empty_snapshot(monkeypatch):
|
||||
)
|
||||
|
||||
file_list = [types.SimpleNamespace(id="doc-1")]
|
||||
await _FakeSync((iter(()), file_list))._run_task_logic(_make_task())
|
||||
task = {**_make_task(), "task_type": sync_data_source.ConnectorTaskType.PRUNE}
|
||||
sync = _FakeSync(iter(()))
|
||||
sync.conf["sync_deleted_files"] = True
|
||||
sync.connector = types.SimpleNamespace(
|
||||
retrieve_all_slim_docs_perm_sync=lambda: iter((file_list,))
|
||||
)
|
||||
|
||||
await sync._run_task_logic(task)
|
||||
|
||||
assert cleanup_calls == [
|
||||
(
|
||||
@@ -285,12 +345,13 @@ async def test_rdbms_generate_keeps_deleted_file_snapshot_without_timestamp_colu
|
||||
}
|
||||
)
|
||||
|
||||
document_generator, file_list = await sync._generate(task)
|
||||
document_generator = await sync._generate(task)
|
||||
connector = _FakeRDBMSConnector.instance
|
||||
|
||||
assert connector is not None
|
||||
assert connector.load_from_state_called is True
|
||||
assert connector.load_from_cursor_range_called is False
|
||||
file_list = sync._collect_prune_snapshot(task)
|
||||
assert connector.retrieve_all_slim_docs_perm_sync_called is True
|
||||
assert file_list is not None
|
||||
assert [doc.id for doc in file_list] == ["row-1"]
|
||||
@@ -447,14 +508,15 @@ async def test_dropbox_generate_returns_snapshot_when_sync_deleted_enabled(monke
|
||||
}
|
||||
)
|
||||
|
||||
document_generator, file_list = await sync._generate(task)
|
||||
document_generator = await sync._generate(task)
|
||||
connector = _FakeDropboxConnector.instance
|
||||
|
||||
assert list(document_generator) == [["poll-sync"]]
|
||||
file_list = sync._collect_prune_snapshot(task)
|
||||
assert [doc.id for doc in file_list] == ["dropbox:id-1", "dropbox:id-2"]
|
||||
assert connector.credentials == {"dropbox_access_token": "token-1"}
|
||||
assert connector.retrieve_all_slim_docs_perm_sync_called is True
|
||||
assert connector.snapshot_called_before_poll is True
|
||||
assert connector.snapshot_called_before_poll is False
|
||||
assert connector.poll_source_call[0] == poll_start.timestamp()
|
||||
assert connector.poll_source_call[1] >= poll_start.timestamp()
|
||||
|
||||
@@ -477,11 +539,12 @@ async def test_dropbox_generate_skips_snapshot_for_full_reindex(monkeypatch):
|
||||
}
|
||||
)
|
||||
|
||||
document_generator, file_list = await sync._generate(task)
|
||||
document_generator = await sync._generate(task)
|
||||
connector = _FakeDropboxConnector.instance
|
||||
|
||||
assert list(document_generator) == [["full-sync"]]
|
||||
assert file_list is None
|
||||
assert connector.load_from_state_called is True
|
||||
assert connector.retrieve_all_slim_docs_perm_sync_called is False
|
||||
file_list = sync._collect_prune_snapshot(task)
|
||||
assert [doc.id for doc in file_list] == ["dropbox:id-1", "dropbox:id-2"]
|
||||
assert connector.retrieve_all_slim_docs_perm_sync_called is True
|
||||
assert connector.poll_source_called is False
|
||||
|
||||
Reference in New Issue
Block a user