Реализация автоматического обновления цен товаров из внешних источников
В интернет-магазине с 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% и исключите ручные ошибки. Получите индивидуальное коммерческое предложение уже сегодня.







