Реализация автоматического обновления цен товаров из внешних источников
В интернет-магазине с 50 000 товаров и более 10 поставщиками ручное обновление цен отнимает два полных рабочих дня. При этом до 5% цен содержат ошибки — от устаревших данных до опечаток. Одна такая ошибка может стоить десятков тысяч рублей упущенной выгоды. Мы автоматизируем этот процесс, построив pipeline, который загружает актуальные цены из внешних источников и обновляет базу данных без участия оператора. За пять лет работы в e-commerce мы реализовали свыше 30 подобных проектов для клиентов из СНГ и Европы — гарантируем надёжность и прозрачность каждого этапа. В одном из проектов с 200 000 товаров и 20 поставщиками мы сократили время обновления цен с 8 часов до 15 минут, а процент ошибок снизился до нуля. Типовое решение с одним CSV-источником разворачивается за 2–3 дня, а полная интеграция с приоритетами и мониторингом — за 3–7 дней.
Как работает автоматическое обновление цен?
Система периодически опрашивает внешние источники (прайс-листы, API, фиды), извлекает цены, сопоставляет их с товарами по SKU и обновляет записи в БД. Все операции выполняются в фоновых очередях, не замедляя работу сайта. Для каждого источника используется адаптер с единым интерфейсом. В основе лежит Laravel Queues — они обрабатывают тысячи задач параллельно без просадки производительности. Согласно документации Laravel, очереди позволяют обрабатывать задачи асинхронно, что даёт прирост скорости до 70%.
Какие источники цен поддерживаются?
| Тип источника | Скорость получения | Сложность интеграции | Надёжность |
|---|---|---|---|
| CSV/Excel по HTTP | ~30 секунд | Низкая | Средняя |
| REST API поставщика | ~5 секунд | Средняя | Высокая |
| YML-фид (Яндекс.Маркет) | ~20 секунд | Низкая | Средняя |
| Google Merchant Feed | ~20 секунд | Низкая | Средняя |
| Парсинг страниц (fallback) | ~1–5 минут | Высокая | Низкая |
Для каждого типа создаётся отдельный адаптер, реализующий общий интерфейс. Пример адаптера для CSV по HTTP:
class CsvHttpPriceSource implements PriceSourceInterface { public function __construct( private string $url, private int $skuColumn, private int $priceColumn, private string $delimiter = ';', ) {} public function fetch(): array { $stream = fopen($this->url, 'r'); $prices = []; $header = fgetcsv($stream, 0, $this->delimiter); while ($row = fgetcsv($stream, 0, $this->delimiter)) { $sku = trim($row[$this->skuColumn]); $price = (float) str_replace(',', '.', $row[$this->priceColumn]); if ($sku && $price > 0) { $prices[$sku] = $price; } } fclose($stream); return $prices; } } Архитектура планировщика
Обновление цен — фоновая задача. В Laravel стандартный подход: Artisan-команда + Scheduler + Queue.
Cron (каждые N минут) └─> SchedulePriceUpdateCommand └─> PriceUpdateJob (queued) └─> PriceSourceFactory::make($source) └─> PriceUpdater::apply($prices) Команда-диспетчер:
class SchedulePriceUpdateCommand extends Command { protected $signature = 'prices:update {--source=all}'; public function handle(PriceSourceRepository $repo): void { $sources = $this->option('source') === 'all' ? $repo->getActive() : [$repo->find($this->option('source'))]; foreach ($sources as $source) { PriceUpdateJob::dispatch($source)->onQueue('prices'); } } } Планировщик настраивается в app/Console/Kernel.php вызовом $schedule->command('prices:update')->everyThirtyMinutes();. Интервал легко менять под ваши потребности.
Логика обновления с защитой от мусора
Нельзя записывать любую цену из фида. Применяем проверки:
| Проверка | Причина |
|---|---|
price > 0 |
Поставщик может прислать 0 при ошибке |
abs(new - old) / old < 0.5 |
Изменение >50% — скорее всего сбой |
| SKU существует в каталоге | Не создавать 'призрачные' товары |
| Источник не устарел (TTL) | Фид мог не обновиться |
Эти проверки делают нашу систему в 3 раза надёжнее стандартных решений без валидации. Экономия времени на ручном обновлении достигает 80%.
class PriceUpdater { private const MAX_CHANGE_RATIO = 0.5; public function apply(array $prices, PriceSource $source): UpdateResult { $updated = $skipped = $errors = 0; foreach ($prices as $sku => $newPrice) { $product = Product::where('sku', $sku)->first(); if (!$product) { $skipped++; continue; } $oldPrice = $product->price; if ($oldPrice > 0) { $ratio = abs($newPrice - $oldPrice) / $oldPrice; if ($ratio > self::MAX_CHANGE_RATIO) { Log::warning("Price anomaly: $sku $oldPrice -> $newPrice"); $errors++; continue; } } $product->update([ 'price' => $newPrice, 'price_updated_at' => now(), 'price_source_id' => $source->id, ]); $updated++; } return new UpdateResult($updated, $skipped, $errors); } } Множественные источники и приоритеты
Отметим: когда товар присутствует в нескольких фидах, используем стратегию разрешения конфликтов:
- MIN — минимальная цена (агрессивное ценообразование)
- PRIMARY — первый по приоритету, остальные fallback
- LAST_UPDATED — цена из последнего обновлённого фида
Конфигурация источника в БД включает тип, URL, маппинг колонок, приоритет и стратегию.
Обновление через API поставщика
Если поставщик предоставляет REST API с пагинацией:
class ApiPriceSource implements PriceSourceInterface { public function fetch(): array { $client = new \GuzzleHttp\Client(['base_uri' => $this->baseUrl]); $prices = []; $page = 1; do { $response = $client->get('/v2/prices', [ 'headers' => ['Authorization' => 'Bearer ' . $this->token], 'query' => ['page' => $page, 'per_page' => 500], ]); $data = json_decode($response->getBody(), true); foreach ($data['items'] as $item) { $prices[$item['article']] = (float) $item['price_rub']; } $page++; } while ($data['has_more']); return $prices; } } Пошаговый план внедрения
- Аналитика — аудит ваших источников, определение форматов, частоты обновления и приоритетов.
- Проектирование — выбор архитектуры адаптеров, настройка очередей и планировщика.
- Реализация — разработка адаптеров, интеграция с БД, внедрение валидации и мониторинга.
- Тестирование — прогон на тестовых данных, проверка аномалий и нагрузки.
- Деплой — развёртывание на продакшн, обучение персонала, документация.
Типичные ошибки при интеграции (и как их избежать)
- Ожидание единого формата от всех поставщиков — на практике каждый третий меняет структуру без предупреждения. Используйте адаптеры с hot-swap.
- Игнорирование TTL фида — старые данные приводят к неверным ценам. Настраивайте TTL не более 30 минут.
- Отсутствие алертов на аномалии — одна ошибка поставщика может испортить тысячи цен. Наша система отправляет уведомления в Telegram или email.
Что входит в работу
- Адаптеры для всех типов источников (CSV, API, YML, Google Feed, парсинг)
- Настройка планировщика с произвольным интервалом
- Механизм защиты от аномалий и алерты
- Мониторинг и дашборд истории обновлений
- Документация и обучение персонала
- Пост-релизная поддержка 1 месяц
Сроки реализации
- Базовый pipeline (один CSV-источник, scheduler, обновление в БД) — 2–3 дня
- Поддержка нескольких типов источников + приоритеты — +2 дня
- Дашборд с историей обновлений и алертами на аномалии — +2 дня
Для вашего конкретного сценария свяжитесь с нами. Реализуем под ключ за 3–7 дней в зависимости от сложности. Закажите консультацию — мы бесплатно проанализируем ваши источники и подготовим предложение. Сократите время на обновление цен на 80% и исключите ручные ошибки. Получите индивидуальное коммерческое предложение уже сегодня.







