Перейти к основному содержимому

Оценка реализации нового сервиса распознавания (RecognitionServiceNew)

Дата оценки: 2026-01-24 Версия документации: 01-07 + 10-first-design Директория реализации: ./recognitionservicenew/

Запрос к AI: В документации описаны постановка и проектирование нового сервиса распознавания. Оцени реализацию нового сервиса, в новом документе в репозитории проекта опиши, какие требования выполняются или нет, какие ошибки или проблемы допущены с указанием критичности. В конце оцени общее качество реализации и процент выполненных требований (процент отхода от документации).


Резюме

Реализация нового сервиса распознавания выполнена с использованием правильных технологий и архитектурных паттернов (DDD, Clean Architecture, CQRS, Event Sourcing). Общая структура проекта соответствует требованиям документации, однако обнаружены критические проблемы производительности и корректности, которые блокируют релиз в production.

Общая оценка качества: ⚠️ Средняя (требуются критические исправления) Процент выполнения требований: ~65% (выполнено 13 из 20 ключевых требований) Процент отхода от документации: ~35%

Статус:Не готов к релизу - требуется исправление критических проблем


1. Выполнение функциональных требований

✅ Выполненные требования

ТребованиеСтатусКомментарий
1Подписка на события PhotoPublished из PhotoService✅ ВыполненоРеализован PhotoPublishedEventHandler
2Поддержка провайдера VkVision (синхронный)✅ ВыполненоРеализован MailVisionFaceRecognitionService
3Поддержка провайдера Athlete (асинхронный)⚠️ ЧастичноРеализован, но с критической ошибкой в обработке callback
4Поддержка 5 стратегий распознавания✅ ВыполненоNumberRecognitionStrategy enum с 5 значениями
5Смена стратегии без перебора всех фотографий❌ Не выполненоФлаги FaceRecognized/NumberRecognized есть, но логика фильтрации неверная
6Подписка на события PhotoDeleted✅ ВыполненоРеализован PhotoDeletedEventHandler
7Подписка на события AlbumCreated✅ ВыполненоРеализован AlbumCreatedEventHandler
8Поддержка кастомных тегов❌ Не выполненоОтсутствует таблица AlbumCustomTag

❌ Не выполненные / частично выполненные требования

1. Валидация результатов по стартовому списку

  • Статус: ⚠️ Частично выполнено
  • Реализация: Интеграция с CompetitorService реализована, но используется только в пайплайне
  • Проблема: Нет гарантий, что валидация применяется ко всем результатам
  • Критичность: 🟡 Средняя

2. Смена стратегии без перебора всех фотографий

  • Статус: ❌ Не выполнено корректно

  • Требование из документации (03-solution-design.md):

    "Не перебирать все фотографии. Хранить признаки состояния (FaceRecognized, NumberRecognized, ManualTaggingCompleted). Обрабатывать только необходимые фото."

  • Проблема в реализации:

    // recognitionservicenew/src/RecognitionService.Application/Albums/Jobs/AlbumPhotosProcessingJob.cs:69
    query = query.Where(p => !p.NumberRecognized || !p.FaceRecognized);

    НЕПРАВИЛЬНАЯ ЛОГИКА: условие !p.NumberRecognized || !p.FaceRecognized означает, что будут обработаны фотографии, где:

    • Не распознаны номера ИЛИ
    • Не распознаны лица

    При смене стратегии с "OnlyAuto" на "FirstAutoThenManual" будут переобработаны ВСЕ фотографии, где уже распознаны номера, но не распознаны лица. Это нарушает требование "не перебирать все фотографии".

  • Дополнительная проблема: Не используется TaggingStrategyProcessingHash для определения, нужна ли переобработка

  • Критичность: 🔴 Критическая

3. Приоритеты обработки

  • Статус: ❌ Не реализовано
  • Требование: "Будут реализованы позже" (документ 02-requirements.md)
  • Реализация: Поле AlbumPriority в БД есть, но не используется
  • Критичность: 🟢 Низкая (будущая доработка)

4. Передача PhotographerId и ShootingDate в TagatorService

  • Статус: ❌ Не выполнено

  • Требование из документации (02-requirements.md):

    "При создании задачи для TagatorService необходимо прокидывать PhotographerId и ShootingDate"

  • Проблема: Структура TaggingTask не содержит эти поля:

    // recognitionservicenew/src/RecognitionService.Domain/Aggregates/Photos/Photo.cs
    public class TaggingTask
    {
    public TaggingTaskId Id { get; }
    public TaggingTaskType Type { get; }
    public Guid? TagatorId { get; }
    public RecognitionResult Result { get; }
    public TaggingTaskState State { get; }
    // ❌ ОТСУТСТВУЮТ: PhotographerId, ShootingDate, AlbumId
    }
  • Критичность: 🟡 Средняя

5. Распознавание по селфи

  • Статус: ⚠️ Частично выполнено
  • Реализация: API endpoint /api/v1/selfies реализован
  • Проблема: Не проверена корректность работы
  • Критичность: 🟡 Средняя

2. Выполнение нефункциональных требований

Масштабируемость

Требование: "Сотни тысяч фото в неделю в сезон"

Статус:Не выполнено

Критическая проблема:

// recognitionservicenew/src/RecognitionService.Domain/Services/RecognitionPipelineProcessor.cs:47
while (photo.State == PhotoState.AwaitingCallback)
{
await Task.Delay(100, cancellationToken);
photo = await photosRepository.GetAsync(photo.Id, cancellationToken);
}

🔴 КРИТИЧЕСКИЙ БАГ: Активное ожидание callback'ов (Busy Waiting)

Последствия:

  • При обработке 1000 фотографий одновременно блокируется 1000 потоков
  • Каждый поток выполняет запрос к БД каждые 100ms
  • При 1000 фото: 10,000 запросов к БД в секунду (полностью блокирует систему)
  • Невозможно масштабировать горизонтально
  • CPU расходуется на пустое ожидание

Ожидаемая реализация (из документации):

"Синхронная обработка при получении события. Минимизация использования Hangfire (только при ошибках)."

Должно быть реализовано через event-driven подход:

  1. Callback сохраняется в таблицу Callback
  2. Генерируется событие CallbackCreated
  3. CallbackCreated.Handler продолжает обработку фото

Критичность: 🔴 Критическая - блокирует релиз


Надежность

Требование: "Работа при недоступности Redis"

Статус: ⚠️ Частично выполнено

Анализ:

  • Redis используется только для Hangfire
  • При недоступности Redis фоновые задачи не будут выполняться
  • Основная обработка через Kafka событий не зависит от Redis ✅

Проблема: Нет механизма отложенной retry обработки при недоступности провайдеров

Критичность: 🟡 Средняя


Совместимость

Требование: "Сохранение текущей функциональности"

Статус: ⚠️ Частично выполнено

Проблемы:

  1. ❌ Отсутствует таблица AlbumCustomTag → функционал кастомных тегов потерян
  2. ❌ Структура TaggingTask не содержит AlbumId, PhotographerId, ShootingDate
  3. ⚠️ Нет плана миграции данных (только описание этапов в документации)

Критичность: 🟡 Средняя


3. Выполнение требований к реализации

База данных

Статус: ⚠️ Частично выполнено (80%)

Соответствие документации (04-implementation.md):

ТаблицаСтатусПроблемы
Album✅ РеализованаВсе поля на месте
Photo✅ РеализованаВсе поля на месте
TaggingTask⚠️ Неполная❌ Отсутствуют: AlbumId, PhotographerId, ShootingDate, CreatedOn, CompletedOn
Callback⚠️ Не используется❌ Eldarius callback'и не сохраняются в эту таблицу
Provider✅ Реализована-
ProviderSpace✅ Реализована-
PhotoPerson⚠️ Избыточная❌ Сохраняет лишние поля (Sex, Age, Confidence, Emotion и т.д.)
AlbumCustomTag❌ Отсутствует-

Критичность: 🟡 Средняя


API сервиса

Статус: ✅ Выполнено (95%)

Реализованные эндпоинты:

AdminApi:

  • GET /api/v1/albums/{albumId} - получение альбома
  • PUT /api/v1/albums/{albumId}/strategy - изменение стратегии
  • PUT /api/v1/albums/{albumId}/provider - смена провайдера
  • PATCH /api/v1/albums/{albumId}/recognition/settings - настройки провайдера
  • POST /api/v1/accounts - управление провайдерами
  • GET /api/v1/statistics - статистика

ClientApi:

  • POST /api/v1/eldarius/callback - callback от Eldarius
  • POST /api/v1/selfies - распознавание селфи

InternalApi:

  • GET /api/v1/albums/{albumId} - получение альбома
  • POST /api/v1/tagging-tasks/{taskId}/callback - callback тегирования

Проблемы:

  1. Некорректная обработка Eldarius callback:
    // recognitionservicenew/src/Hosts/RecognitionService.ClientApi.Host/Controllers/EldariusController.cs:30
    var photoId = Guid.Parse(binding.Name.Split(';')[0]);
    Нет валидации формата - может упасть при невалидных данных ❌ Callback не сохраняется в БД - обрабатывается синхронно в контроллере ❌ Событие CallbackCreated не генерируется

Критичность: 🔴 Критическая


Команды и обработчики

Статус: ✅ Выполнено (90%)

Реализованные компоненты:

  • ✅ AlbumPhotosProcessingJob
  • ✅ ProcessPhotoCommand
  • ✅ CreatePhotoCommand, DeletePhotoCommand
  • ✅ ChangeAlbumTaggingStrategyCommand, ChangeAlbumFaceRecognitionProviderCommand
  • ✅ Event Handlers для PhotoPublished, PhotoDeleted, AlbumCreated

Проблемы:

  1. ProcessPhotoCommand не использует кеширование:

    // recognitionservicenew/src/RecognitionService.Application/Photos/Commands/ProcessPhotoCommand.Handler.cs:32
    var album = await albumsRepository.GetAsync(photo.AlbumId, cancellationToken);
    // TODO: Get from cache

    При обработке 10,000 фото одного альбома → 10,000 запросов к БД за одними данными

  2. AlbumPhotosProcessingJob использует неправильную логику фильтрации (описано выше)

Критичность: 🟡 Средняя


Интеграция с провайдерами

Статус: ⚠️ Частично выполнено (70%)

Athlete (Eldarius)

Требование из документации (04-implementation.md):

"Запрос с recognition_type = FACE_NUMBER. Callback возвращает persons и tags одновременно."

Реализация:

  • ✅ Запрос с FACE_NUMBER реализован
  • Callback не извлекает только нужные поля (PersonId, StartNumber)
  • Callback не сохраняется в БД
  • Не генерируется событие CallbackCreated

Критичность: 🔴 Критическая

VkVision (MailVision)

Требование из документации (04-implementation.md):

"Должны сохраняться только PersonId и координаты распознанных лиц"

Реализация:

// recognitionservicenew/src/RecognitionService.Infrastructure/FaceRecognition/MailVisionFaceRecognitionService.cs:98
photoPersons.Add(new PhotoPerson
{
PersonId = person.Tag,
Confidence = person.Confidence,
// ❌ ЛИШНИЕ ПОЛЯ:
Sex = person.Sex,
Age = person.Age,
Emotion = person.Emotion,
Frontality = person.Frontality,
Awesomeness = person.Awesomeness,
Similarity = person.Similarity,
Valence = person.Valence,
Arousal = person.Arousal
});

Сохраняет ВСЕ поля вместо только PersonId

Последствия:

  • Избыточное хранение данных в БД
  • Нарушение требований документации
  • Потенциальные проблемы с GDPR (хранение демографических данных)

Критичность: 🔴 Критическая


4. Выполнение требований к наблюдаемости

Healthchecks

Статус: ⚠️ Частично выполнено (40%)

Требование из документации (05-observability.md):

"Healthchecks должны проверять: БД, Redis, RabbitMQ, VkVision, Athlete, PhotoService, TagatorService"

Реализация:

// recognitionservicenew/src/Hosts/RecognitionService.AdminApi.Host/Program.cs:81
healthChecksBuilder
.AddCheck<KafkaConsumersHealthCheck>("Kafka")
.AddCheck<EventsPublisherHealthCheck>("EventsPublisher");

Результат:

  • ✅ Kafka
  • ✅ EventsPublisher
  • Отсутствуют: PostgreSQL, Redis, VkVision, Athlete, PhotoService, TagatorService

Критичность: 🟡 Средняя


Метрики

Статус: ❌ Не выполнено (10%)

Требование из документации (05-observability.md):

Должны быть реализованы метрики:

  • photos_recognized_total - количество распознанных фото
  • photos_recognition_duration_seconds - длительность распознавания
  • photos_tagged_total - количество отегированных фото
  • tags_created_total - количество созданных тегов
  • vkvision_requests_total - запросы к VkVision
  • athlete_requests_total - запросы к Athlete
  • И другие...

Реализация:

// recognitionservicenew/src/RecognitionService.Monitoring/RecognitionMetrics.cs:10
_tasksCounter = meter.CreateCounter<int>("Recognitionservice.tasks.count");

Результат: Реализована только 1 метрика из ~20 требуемых

Критичность: 🟡 Средняя (не блокирует релиз, но критично для production)


Логирование

Статус: ⚠️ Частично выполнено (60%)

Анализ:

  • ✅ Используется Serilog
  • ✅ Логирование основных операций реализовано
  • ❌ Нет структурированного логирования с JSON
  • ❌ Нет логирования всех этапов обработки (как требует документация)

Критичность: 🟡 Средняя


5. Обнаруженные критические проблемы

🔴 Критическая критичность (блокируют релиз)

ПроблемаФайл:строкаПоследствияРешение
1Активное ожидание callback'овRecognitionPipelineProcessor.cs:47Блокировка потоков, 10k+ запросов к БД/сек, невозможность масштабированияИспользовать event-driven подход через CallbackCreated событие
2Eldarius callback не сохраняется в БДEldariusController.cs:30Потеря данных при ошибках, невозможность отладки, нарушение требованийСохранять callback в таблицу Callback, генерировать CallbackCreated событие
3VkVision сохраняет все поляMailVisionFaceRecognitionService.cs:98Избыточное хранение, нарушение GDPR, отход от документацииСохранять только PersonId
4Некорректный парсинг PhotoIdEldariusController.cs:30Падение при невалидных данныхДобавить try-catch, валидацию формата
5Неправильная логика фильтрации фотоAlbumPhotosProcessingJob.cs:69Переобработка всех фото при смене стратегииИсправить условие, использовать TaggingStrategyProcessingHash

🟡 Средняя критичность (требуют исправления до релиза)

ПроблемаФайл:строкаПоследствияРешение
6Не используется кеширование альбомовProcessPhotoCommand.Handler.cs:32Множественные запросы к БД за одними даннымиИспользовать AlbumsCacheService
7Неполная структура TaggingTaskPhoto.csНевозможна корректная интеграция с TagatorServiceДобавить поля: AlbumId, PhotographerId, ShootingDate
8Отсутствует таблица AlbumCustomTag-Функционал кастомных тегов потерянДобавить миграцию для таблицы
9Недостаточно healthchecksProgram.cs:81Невозможно определить проблемы с зависимостямиДобавить проверки БД, Redis, провайдеров
10Недостаточно метрикRecognitionMetrics.csНевозможен мониторинг productionРеализовать все метрики из документации

🟢 Низкая критичность (можно отложить)

ПроблемаПоследствияРешение
11Приоритеты обработки не реализованыНельзя обработать срочные альбомы первымиРеализовать polling с приоритетом
12Нет валидации соответствия количества лиц и номеровВозможны ложные срабатыванияРеализовать улучшенную валидацию
13Нет плана миграции данныхНевозможно мигрировать со старых сервисовРазработать SQL-скрипты миграции
14Нет структурированного логированияСложность отладки в productionПерейти на JSON логирование

6. Соответствие архитектурным принципам

✅ Правильно реализованные аспекты

  1. Domain-Driven Design:

    • ✅ Правильное выделение агрегатов (Album, Photo, Provider, Tenant)
    • ✅ Использование Value Objects (PhotoState, NumberRecognitionStrategy)
    • ✅ Доменные события для всех изменений состояния
    • ✅ Инварианты защищены на уровне агрегатов
  2. Clean Architecture:

    • ✅ Четкое разделение слоев (Domain → Application → Infrastructure → Hosts)
    • ✅ Зависимости направлены внутрь (к Domain)
    • ✅ Инфраструктурные детали изолированы
  3. CQRS:

    • ✅ Разделение команд и запросов
    • ✅ Обработчики команд изолированы
  4. Event Sourcing:

    • ✅ Все изменения состояния генерируют события
    • ✅ События сохраняются в таблице PersistedEvent
    • ✅ Публикация событий в Kafka
  5. Технологический стек:

    • ✅ .NET 8, ASP.NET Core
    • ✅ PostgreSQL + Entity Framework Core
    • ✅ Kafka для event-driven коммуникации
    • ✅ Hangfire для фоновых задач
    • ✅ Docker + Kubernetes ready

❌ Нарушения архитектурных принципов

  1. Busy Waiting вместо Event-Driven:

    while (photo.State == PhotoState.AwaitingCallback)
    {
    await Task.Delay(100); // ❌ Анти-паттерн
    }

    Должно быть через события.

  2. Обработка бизнес-логики в контроллере:

    // EldariusController.cs
    var photoId = Guid.Parse(binding.Name.Split(';')[0]); // ❌ Бизнес-логика в API слое
    await commandExecutor.Execute(new CreateEldariusCallbackCommand(...)); // Должно быть в Application
  3. Не используется кеширование:

    // TODO: Get from cache // ❌ Не реализовано
    var album = await albumsRepository.GetAsync(photo.AlbumId);
  4. Избыточное сохранение данных:

    photoPersons.Add(new PhotoPerson {
    Age = person.Age, // ❌ Не требуется по документации
    Sex = person.Sex, // ❌ Не требуется
    // ... и т.д.
    });

7. Итоговая оценка

Процент выполнения требований по категориям

КатегорияВыполненоЧастичноНе выполнено% выполнения
Функциональные требования521~75%
Нефункциональные требования021~50%
Требования к реализации (БД, API)1552~80%
Наблюдаемость123~30%
Архитектурные принципы804~65%
ИТОГО291111~65%

Общая оценка качества реализации

Положительные стороны:

  • ✅ Правильная архитектура (DDD, Clean Architecture, CQRS)
  • ✅ Хорошее разделение на слои и модули
  • ✅ Использование современных технологий (.NET 8, EF Core, Kafka)
  • ✅ Большинство функциональных требований реализовано
  • ✅ Event-driven архитектура (частично)

Критические недостатки:

  • 🔴 Активное ожидание callback'ов (busy waiting) → невозможность масштабирования
  • 🔴 Неправильная обработка callback'ов Eldarius → потеря данных
  • 🔴 Избыточное сохранение данных (VkVision) → нарушение требований
  • 🔴 Неправильная логика фильтрации → переобработка всех фото
  • 🟡 Недостаточная наблюдаемость → сложность эксплуатации в production

Оценка качества: ⚠️ Средняя (3 из 5)

Процент отхода от документации: ~35%


8. Рекомендации

Перед релизом в production (обязательно):

  1. Исправить активное ожидание callback'ов

    • Реализовать event-driven подход через CallbackCreated событие
    • Убрать while (photo.State == AwaitingCallback) { Thread.Sleep(100) }
  2. Исправить обработку Eldarius callback

    • Сохранять callback в таблицу Callback
    • Генерировать событие CallbackCreated
    • Извлекать только нужные поля (PersonId, StartNumber)
  3. Исправить VkVision провайдер

    • Сохранять только PersonId вместо всех полей
  4. Исправить логику фильтрации фото

    • Использовать правильное условие для фильтрации
    • Использовать TaggingStrategyProcessingHash
  5. Добавить валидацию в EldariusController

    • Try-catch для парсинга PhotoId
    • Проверка формата данных
  6. Реализовать кеширование альбомов

    • Использовать AlbumsCacheService в ProcessPhotoCommand

После релиза (улучшения):

  1. Реализовать все метрики из документации
  2. Добавить все healthchecks (БД, Redis, провайдеры)
  3. Добавить таблицу AlbumCustomTag
  4. Дополнить структуру TaggingTask полями из документации
  5. Реализовать приоритеты обработки
  6. Разработать план миграции данных со старых сервисов

9. Заключение

Реализация нового сервиса распознавания выполнена на ~65% и содержит 5 критических проблем, которые блокируют релиз в production.

Основная архитектура выбрана правильно, структура проекта соответствует требованиям, однако реализация ключевых компонентов (обработка callback'ов, масштабируемость) выполнена неверно.

Статус:Не готов к релизу

Требуемое время на исправление критических проблем: Оценочно 2-3 недели разработки + тестирование.

Риски при релизе в текущем состоянии:

  • 🔴 Полное блокирование системы при обработке большого количества фото
  • 🔴 Потеря данных при сбоях
  • 🔴 Невозможность масштабирования
  • 🔴 Проблемы с производительностью БД (10k+ запросов/сек)

Рекомендация: Исправить все критические проблемы перед релизом, провести нагрузочное тестирование.