---
id: entity-rag-index-job
title: Сущность IndexJob
doc_type: domain_entity
domain: rag
status: draft
owner: system-analyst
source_of_truth: code
related_docs:
  - arch-rag-package
  - logic-rag-indexing
  - entity-rag-session
  - api-rag-session-job
related_code:
  - src/app/modules/rag/job_store.py
  - src/app/modules/rag/indexing_service.py
  - src/app/modules/rag/persistence/job_repository.py
  - src/app/modules/rag/persistence/schema_repository.py
entities:
  - IndexJob
  - RagSession
tags:
  - rag
  - indexing
  - job
  - domain-entity
---
# Сущность IndexJob

## Summary
- Domain: rag
- Purpose: представить асинхронную задачу индексации и её наблюдаемый статус.
- Entity role: operational entity для выполнения snapshot/change indexing.
- Main attributes: `index_job_id`, `rag_session_id`, `status`, `indexed_files`, `failed_files`, `cache_hit_files`, `cache_miss_files`, `error`.
- Lifecycle: `queued -> running -> done|error`.
- Invariants: job всегда принадлежит одной `RagSession`, статус хранится как enum `IndexJobStatus`.
- Related APIs: создание job косвенно через session endpoints, чтение через job status endpoint и SSE endpoint.
- Related logic: `IndexingOrchestrator`, retry, EventBus publishing.
- Source of truth: `src/app/modules/rag/job_store.py`, `src/app/modules/rag/indexing_service.py`.

## Назначение

`IndexJob` хранит технический прогресс и итог выполнения индексации. Он нужен, чтобы API модуля мог вернуть результат не синхронно, а через опрос статуса и подписку на события.

## Контекст

Job создаётся на каждую snapshot- или changes-операцию. Сервис индексации обновляет его counters и публикует события прогресса в EventBus под ключом `index_job_id`.

## Роль в доменной модели

Это операционная сущность, которая связывает пользовательский запрос на индексацию с фактическим процессом обработки файлов. Она не хранит сам индекс, но управляет прозрачностью выполнения и ошибками.

## Атрибуты

| attribute | type | required | description | constraints |
|-----------|------|----------|-------------|-------------|
| `index_job_id` | `str` | yes | уникальный идентификатор задачи | primary key, non-empty |
| `rag_session_id` | `str` | yes | ссылка на целевую RAG-сессию | non-empty |
| `status` | `IndexJobStatus` | yes | текущее состояние задачи | `queued`, `running`, `done`, `error` |
| `indexed_files` | `int` | yes | число успешно обработанных файлов | `>= 0` |
| `failed_files` | `int` | yes | число файлов с ошибками | `>= 0` |
| `cache_hit_files` | `int` | yes | число файлов, обслуженных из cache | `>= 0` |
| `cache_miss_files` | `int` | yes | число файлов, потребовавших embeddings | `>= 0` |
| `error` | `ErrorPayload \| None` | no | информация о необработанной временной ошибке после retry | optional |

## Состояния и жизненный цикл

### Основные состояния
- `queued`
- `running`
- `done`
- `error`

### Переходы состояний
1. `IndexJobStore.create` создаёт job в состоянии `queued`.
2. `IndexingOrchestrator._run_with_project_lock` переводит job в `running`.
3. Успешная индексация переводит job в `done` и заполняет counters.
4. Ошибка после исчерпания retry переводит job в `error` и заполняет `ErrorPayload`.

## Инварианты и ограничения

- Job не мигрирует между `rag_session_id`.
- Финальные counters сохраняются в БД перед публикацией terminal event.
- Ошибки уровня `TimeoutError`, `ConnectionError`, `OSError` считаются временными и оборачиваются в `index_retry_exhausted` только после retry exhaustion.

## Связи с другими сущностями

| entity | relation | description |
|--------|----------|-------------|
| `RagSession` | many-to-one | каждая задача относится к одной сессии |
| `RagDocument` | indirect | job обновляет набор документов сессии, но не владеет ими напрямую |

## Использование в системе

### Related API
- `POST /api/rag/sessions`
- `POST /api/rag/sessions/{rag_session_id}/changes`
- `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}`
- `GET /api/rag/sessions/{rag_session_id}/jobs/{index_job_id}/events`

### Related UI
- Прямого UI в репозитории не обнаружено.

### Related logic
- `logic-rag-indexing`

### Related integrations
- EventBus SSE stream
- PostgreSQL таблица `rag_index_jobs`

## Функциональные требования

- Job должна создаваться до запуска фоновой задачи.
- Публичный API обязан проверять принадлежность job указанной `rag_session_id`.
- Progress events должны публиковаться в формате, достаточном для фронта или внешнего клиента.

## Нефункциональные требования

### Audit / history
- `created_at` и `updated_at` сохраняются в таблице `rag_index_jobs`.

### Security
- Доступ к job опирается на проверку связи `job.rag_session_id == requested rag_session_id`.

### Observability
- SSE stream отдаёт `index_status`, `index_progress`, `terminal`.

## Связанный код

### Files
- `src/app/modules/rag/job_store.py`
- `src/app/modules/rag/indexing_service.py`
- `src/app/modules/rag/persistence/job_repository.py`
- `src/app/modules/rag/persistence/schema_repository.py`

### Symbols
- `IndexJob`
- `IndexJobStore.create`
- `IndexJobStore.get`
- `IndexJobStore.save`
- `IndexingOrchestrator._run_with_project_lock`

## Связанные документы

- `arch-rag-package`
- `logic-rag-indexing`
- `entity-rag-session`
- `api-rag-session-job`

## История изменений

| Date | Source | Changes |
|------|--------|---------|
| 2026-03-13 | code | Добавлено описание lifecycle и контракта сущности `IndexJob`. |
