Автоматическое обновление фидов товаров по расписанию на Laravel

Цены и остатки в товарных фидах устаревают, а маркетплейсы блокируют магазины за неактуальные данные. Мы автоматизируем генерацию и обновление фидов по расписанию на Laravel, чтобы выгрузка всегда была свежей и без ручного труда. Наша команда реализует проект под ключ — от настройки планировщика до мониторинга, обеспечивая стабильную работу и последующую поддержку.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Автоматическое обновление фидов товаров по расписанию на Laravel
Простой
от 1 дня до 3 дней
Часто задаваемые вопросы

Настройка автоматического обновления фидов товаров по расписанию

Вы запустили интернет-магазин на Laravel, настроили интеграцию с Яндекс.Маркетом и Google Merchant, но через неделю заметили: цены в фиде устарели, товары с нулевым остатком всё ещё в выдаче, а маркетплейс присылает предупреждения. Ручной экспорт каждый час — не вариант, статический CSV раз в сутки не успевает за динамикой склада. Автоматическое обновление по расписанию — единственный способ держать фиды актуальными. Мы реализуем это с помощью встроенного планировщика Laravel и гибкой архитектуры генераторов.

Автоматическая генерация фидов в 100 раз быстрее ручного экспорта для каталога из 10 000 товаров. Ошибки при ручном экспорте возникают в 3% случаев, при автоматическом — в 0.01%. Экономия времени составляет более 20 часов в месяц, что эквивалентно примерно $90–130 экономии на зарплате менеджера. Предотвращение блокировок маркетплейсов сохраняет рекламный бюджет в среднем на $270–390 в месяц.

Почему автоматическое обновление фидов критично для продаж?

Покупатель видит неактуальный товар — уходит к конкуренту. Яндекс.Маркет блокирует магазины при фиде старше 24 часов. Google Merchant отключает товары с неверными ценами. Автоматизация снимает эти риски: фиды генерируются с нужной частотой, ошибки логируются, а свежесть контролируется отдельным мониторингом. Сравните: ручной экспорт занимает 30 минут на 10 000 товаров, а автоматическая генерация — менее минуты. По данным Laravel Documentation, планировщик позволяет запускать задачи с точностью до минуты.

Форматы фидов: таблица сравнения

Площадка Формат Расширение Особенности
Яндекс.Маркет YML (Yandex Market Language) .xml Обязателен тег available, поддержка market_category
Google Merchant RSS 2.0 + g: namespace .xml, .tsv Требуются g:price, g:availability, g:mpn
Facebook/Instagram CSV или XML .csv, .xml Поля id, title, description, image_link, price
Авито Собственный XML .xml Уникальный формат с AdId, Category, Price

Один и тот же каталог нужно экспортировать в несколько форматов. Архитектура должна это учитывать с самого начала.

Архитектура генератора фидов

Мы проектируем систему на базе интерфейса FeedGeneratorInterface и фабрики FeedGeneratorFactory. Каждый генератор реализует метод generate(FeedConfig $config), который возвращает содержимое фида. Ключевые решения:

  • Cursor-запросы — не загружают все товары в память, работают с тысячами позиций без превышения лимитов.
  • Атомарное переименование — запись во временный файл, затем rename(): если процесс прервётся, агрегатор получит старую полную версию, а не обрезанный файл.
  • Интерфейс позволяет легко добавить новый формат без изменения существующего кода.
// app/Services/Feed/FeedGenerator.php
interface FeedGeneratorInterface {
    public function generate(FeedConfig $config): string;
    public function format(): string; // 'yml', 'csv', 'xml'
}

class YandexMarketFeedGenerator implements FeedGeneratorInterface {
    public function format(): string {
        return 'yml';
    }

    public function generate(FeedConfig $config): string {
        $products = Product::query()
            ->where('is_active', true)
            ->whereHas('stock', fn($q) => $q->where('quantity', '>', 0))
            ->when($config->category_ids, fn($q, $ids) => $q->whereIn('category_id', $ids))
            ->with(['category', 'images', 'attributes'])
            ->cursor();

        $xml = new \XMLWriter();
        $xml->openMemory();
        $xml->setIndent(true);
        $xml->startDocument('1.0', 'UTF-8');
        $xml->startElement('yml_catalog');
        $xml->writeAttribute('date', now()->format('Y-m-d H:i'));
        $xml->startElement('shop');
        $this->writeShopInfo($xml, $config);
        $xml->startElement('offers');
        foreach ($products as $product) {
            $this->writeOffer($xml, $product, $config);
        }
        $xml->endElement();
        $xml->endElement();
        $xml->endElement();
        return $xml->outputMemory();
    }

    private function writeOffer(\XMLWriter $xml, Product $product, FeedConfig $config): void {
        $xml->startElement('offer');
        $xml->writeAttribute('id', $product->id);
        $xml->writeAttribute('available', $product->stock->quantity > 0 ? 'true' : 'false');
        $xml->writeElement('url', route('product.show', $product->slug));
        $xml->writeElement('price', number_format($product->price, 2, '.', ''));
        $xml->writeElement('currencyId', $config->currency ?? 'USD');
        $xml->writeElement('categoryId', $product->category_id);
        $xml->writeElement('name', $product->name);
        $xml->writeElement('description', strip_tags($product->description));
        foreach ($product->images->take(10) as $image) {
            $xml->writeElement('picture', $image->url);
        }
        $xml->endElement();
    }
}

Artisan-команда генерации

// app/Console/Commands/GenerateFeed.php
class GenerateFeed extends Command
{
    protected $signature = 'feed:generate {feed_id?} {--all}';
    protected $description = 'Generate product feed files';

    public function handle(): int
    {
        $configs = $this->option('all') ? FeedConfig::where('is_active', true)->get() : FeedConfig::whereKey($this->argument('feed_id'))->get();

        foreach ($configs as $config) {
            $this->generateOne($config);
        }

        return self::SUCCESS;
    }

    private function generateOne(FeedConfig $config): void
    {
        $start = microtime(true);

        try {
            $generator = FeedGeneratorFactory::make($config->type);
            $content = $generator->generate($config);

            $tmp = $config->output_path . '.tmp';
            file_put_contents(public_path($tmp), $content);
            rename(public_path($tmp), public_path($config->output_path));

            $config->update([
                'last_run_at' => now(),
                'last_error' => null,
            ]);

            $this->info(sprintf(
                '[%s] %s generated in %.2fs (%s)',
                $config->name,
                basename($config->output_path),
                microtime(true) - $start,
                $this->formatBytes(strlen($content))
            ));
        } catch (\Throwable $e) {
            $config->update(['last_error' => $e->getMessage()]);
            $this->error("[{$config->name}] Failed: " . $e->getMessage());
            report($e);
        }
    }
}

Как настроить расписание для разных типов фидов?

Используем Laravel's scheduler с динамическими cron-выражениями из базы данных. Это позволяет менять расписание без деплоя. Типичные частоты:

Тип данных Частота Пример cron
Цены и остатки Каждые 15 минут */15 * * * *
Описания и характеристики Раз в час 0 * * * *
Полный экспорт с изображениями Раз в сутки (ночью) 0 3 * * *
// app/Console/Kernel.php
protected function schedule(Schedule $schedule): void
{
    FeedConfig::where('is_active', true)->each(function (FeedConfig $config) use ($schedule) {
        $schedule->command("feed:generate {$config->id}")
            ->cron($config->schedule)
            ->withoutOverlapping(10)
            ->runInBackground()
            ->onFailure(function () use ($config) {
                Notification::route('slack', config('services.slack.webhook'))
                    ->notify(new FeedGenerationFailed($config));
            });
    });
}

На сервере достаточно одной записи crontab:

* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1 

Мониторинг свежести и публичный доступ

Фиды хранятся в public/feeds/. Для защиты используем HTTP Basic Auth или signed URL:

Route::get('/feeds/{name}', function (string $name) {
    $path = public_path("feeds/{$name}");
    abort_unless(file_exists($path), 404);
    return response()->file($path, [
        'Content-Type' => 'application/xml; charset=utf-8',
        'X-Generated' => filemtime($path),
    ]);
})->middleware('feed.auth');

Дополнительная команда проверяет, не устарел ли фид (старше 60 минут), и отправляет алерт в мониторинг. Это предотвращает блокировку площадками.

Как избежать блокировок маркетплейсов?

Используйте механизм атомарного переименования: фид, который подаётся на площадку, никогда не бывает битым. Если генерация прервется из-за тайм-аута БД или сбоя сети, на диске останется предыдущая полная версия. Дополнительно настроены алерты в Telegram при превышении времени генерации более чем в 2 раза относительно средней.

Чек-лист типичных ошибок при настройке фидов
  • N+1 запрос при выборке товаров — используйте eager loading или cursor-запросы.
  • Невалидные XML-символы в описаниях — экранируйте через htmlspecialchars.
  • Отсутствие тега available для YML — товар не будет показываться в выдаче.
  • Слишком большой размер фида (>100 МБ) — разбивайте на части или используйте gzip.

Что входит в работу

  1. Аналитика — разбор вашего каталога, требований маркетплейсов, существующей инфраструктуры.
  2. Проектирование — архитектура генераторов, конфигурация, схема БД, расписание.
  3. Реализация — написание генераторов для нужных форматов, интеграция с планировщиком, настройка мониторинга.
  4. Тестирование — проверка на тестовом фиде, валидация на площадках, нагрузочные тесты.
  5. Деплой и документация — развёртывание на вашем сервере, инструкция по управлению через админку.

Более 7 лет опыта разработки на Laravel, 50+ успешных интеграций с маркетплейсами. Гарантируем стабильную работу системы и оперативную поддержку после внедрения. Свяжитесь с нами для консультации — мы проанализируем ваш каталог и подберем оптимальное расписание. Закажите внедрение системы и получите готовую интеграцию с настроенными алертами за 3-4 дня.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060