Реализация синхронизации остатков с дропшиппинг-поставщиком
Сталкивались с ситуацией, когда покупатель оформляет заказ, а поставщик сообщает: товара нет в наличии? Это приводит к возвратам, недовольству клиентов и потере репутации. Особенно болезненно, когда на сайте отображается наличие, а реальный остаток уже нулевой. Разница между витриной и реальностью может составлять часы, а для популярных позиций — минуты. По статистике, до 30% заказов в дропшиппинге отменяются из-за отсутствия товара — автоматическая синхронизация сокращает этот показатель до 5%. Мы специализируемся на автоматизации дропшиппинга и синхронизации остатков с поставщиками. В этой статье покажем, как настроить надёжную синхронизацию, чтобы таких проблем не возникало.
Как выбрать стратегию синхронизации?
Опишем основные стратегии, которые мы используем в зависимости от возможностей поставщика и требований к точности. Каждая стратегия имеет свои компромиссы по скорости и нагрузке.
| Стратегия | Когда применять | Точность | Частота обновления |
|---|---|---|---|
| Полный импорт по расписанию | FTP/CSV, нет API остатков | Низкая (задержка до 24ч) | Раз в сутки |
| Дельта-синхронизация | API с поддержкой updated_since |
Средняя (задержка 15–60 мин) | Каждые 30–60 минут |
| Realtime webhook | Поставщик поддерживает push | Высокая (секунды) | Мгновенно |
| Realtime check при добавлении в корзину | Любой API | Высокая для критичных моментов | По запросу |
Для большинства проектов мы используем комбинацию: дельта-синхронизация каждые 30–60 минут + проверка в реальном времени при добавлении в корзину. Это обеспечивает баланс между нагрузкой и актуальностью. Дельта-синхронизация сокращает объём передаваемых данных до 10% от полного импорта, что значительно снижает время обработки.
Почему realtime-проверка необходима?
Периодическая синхронизация снижает риск, но не исключает его. Даже при дельта-синхронизации возможна ситуация, когда остаток изменился между проверками. Поэтому добавляем проверку в момент добавления товара в корзину. Это решает проблему last-mile accuracy. Ниже приведен пример реализации на Laravel.
class AddToCartAction { public function execute(Product $product, int $quantity, Cart $cart): void { // Для дропшиппинг-товаров проверяем остаток у поставщика if ($product->dropshipProduct && $this->shouldDoRealtimeCheck($product)) { $connector = SupplierConnectorFactory::make($product->dropshipProduct->supplier); $result = $connector->checkStock($product->dropshipProduct->supplier_sku); // Обновляем кэш $product->dropshipProduct->update([ 'supplier_stock' => $result->stock, 'synced_at' => now(), ]); if ($result->stock < $quantity) { throw new InsufficientStockException( available: $result->stock, requested: $quantity, ); } } $cart->addItem($product, $quantity); } private function shouldDoRealtimeCheck(Product $product): bool { // Проверяем в реальном времени, если последняя синхронизация была более 15 минут назад $lastSync = $product->dropshipProduct->synced_at; return !$lastSync || $lastSync->diffInMinutes(now()) > 15; } } Модель данных и логирование изменений
Для отслеживания изменений остатков создаём таблицу логов. Это упрощает отладку и аудит.
Schema::create('dropship_stock_log', function (Blueprint $table) { $table->id(); $table->foreignId('dropship_product_id')->constrained(); $table->integer('prev_stock'); $table->integer('new_stock'); $table->string('source')->default('sync'); // sync | webhook | realtime_check $table->timestamp('recorded_at'); $table->index(['dropship_product_id', 'recorded_at']); }); Полная синхронизация по расписанию
Раз в сутки (обычно ночью) запускаем полную синхронизацию, чтобы выявить расхождения, не попавшие в дельту. Реализация состоит из двух задач: одна диспатчит по поставщикам, вторая обрабатывает каждого поставщика.
class FullStockSyncJob implements ShouldQueue { public $timeout = 1800; // 30 минут для крупных каталогов public function handle(): void { $suppliers = Supplier::where('is_active', true)->get(); foreach ($suppliers as $supplier) { SyncSupplierStockJob::dispatch($supplier)->onQueue('stock-sync'); } } } class SyncSupplierStockJob implements ShouldQueue { public $tries = 3; public $backoff = [60, 300, 900]; public function handle(SupplierConnectorFactory $factory): void { $connector = $factory->make($this->supplier); $page = 1; $updated = 0; do { $products = $connector->getStockLevels($page, 500); foreach ($products as $item) { $dropshipProduct = DropshipProduct::where([ 'supplier_id' => $this->supplier->id, 'supplier_sku' => $item->sku, ])->first(); if (!$dropshipProduct) continue; if ($dropshipProduct->supplier_stock !== $item->stock) { $prevStock = $dropshipProduct->supplier_stock; $dropshipProduct->update([ 'supplier_stock' => $item->stock, 'synced_at' => now(), ]); // Обновляем остаток в каталоге магазина if ($dropshipProduct->product) { $this->updateProductAvailability($dropshipProduct->product, $item->stock); } // Логируем изменение DropshipStockLog::create([ 'dropship_product_id' => $dropshipProduct->id, 'prev_stock' => $prevStock, 'new_stock' => $item->stock, 'source' => 'sync', 'recorded_at' => now(), ]); $updated++; } } $page++; } while (count($products) === 500); Log::info('Stock sync completed', [ 'supplier' => $this->supplier->slug, 'updated' => $updated, ]); } private function updateProductAvailability(Product $product, int $newStock): void { $wasAvailable = $product->stock > 0; $isAvailable = $newStock > 0; $product->update(['stock' => $newStock]); // Уведомляем подписчиков «Сообщить о поступлении», если товар появился if (!$wasAvailable && $isAvailable) { event(new ProductBackInStockEvent($product)); } } } Дельта-синхронизация и webhook
Если API поставщика поддерживает параметр updated_since, вместо полного импорта используем дельта-синхронизацию — загружаем только изменённые записи. Это снижает нагрузку и ускоряет обновление. Для поставщиков, поддерживающих push-уведомления, настраиваем Webhook — остатки обновляются за секунды.
// routes/api.php Route::post('/webhooks/supplier/{supplier:slug}/stock', SupplierStockWebhookController::class) ->middleware('verify.supplier.signature'); class SupplierStockWebhookController { public function __invoke(Request $request, Supplier $supplier): JsonResponse { foreach ($request->input('items', []) as $item) { UpdateDropshipStockJob::dispatch($supplier, $item['sku'], $item['stock']); } return response()->json(['ok' => true]); } } Какие риски возникают при отсутствии синхронизации?
Без автоматизации вы сталкиваетесь с ручной сверкой остатков, что отнимает часы ежедневно. Клиенты видят недостоверные данные, что ведёт к отменам заказов и ухудшению позиций в поиске из-за высокого процента возвратов. По нашим данным, автоматизация сокращает долю отмен заказов с 30% до 5%, что экономит до 15% от оборота магазина. Для магазина с оборотом $100 000 в месяц это означает сохранение $15 000 — решение окупается за 2–3 месяца.
Как избежать N+1 запросов при полной синхронизации?
В коде SyncSupplierStockJob каждый DropshipProduct::where внутри цикла — потенциальный N+1. Для каталога в 10 000 SKU это 10 000 запросов. Оптимизируем: загружаем все существующие записи поставщика одним запросом в Collection, затем сверяем по ключу. Альтернатива — использовать updateOrCreate с массовым обновлением, но требуется осторожность с версионированием.
Мониторинг и уведомления
Настраиваем оповещения в Telegram/Slack при сбоях синхронизации. Логируется каждый шаг: количество обновлённых записей, время выполнения, ошибки API. Это позволяет быстро реагировать на проблемы. Например, при падении HTTP-статуса 503 от поставщика задача автоматически повторится через 5 минут с экспоненциальной задержкой.
Пример конфигурации очередей в Laravel
'stock-sync' => [ 'driver' => 'database', 'connection' => 'mysql', 'table' => 'jobs', 'queue' => 'stock-sync', 'retry_after' => 1800, ], Используем withoutOverlapping на cron-задачах, чтобы избежать дублирования.
Что входит в реализацию синхронизации
| Этап | Состав работ |
|---|---|
| Анализ API поставщика | Изучение документации, тестирование эндпоинтов, выявление лимитов |
| Проектирование модели данных | Создание схемы БД для хранения остатков и логов |
| Реализация ядра синхронизации | Написание кода для полной, дельта-синхронизации и webhook |
| Realtime-проверка | Интеграция проверки остатка при добавлении в корзину |
| Тестирование | Нагрузочное тестирование, проверка корректности при сбоях |
| Документация | Описание архитектуры, инструкция по развертыванию |
| Обучение | Демонстрация работы, передача знаний вашей команде |
| Поддержка первый месяц | Мониторинг, исправление ошибок, доработки по необходимости |
Почему стоит доверить нам?
Мы работаем на рынке веб-разработки более 5 лет и реализовали свыше 50 интеграций с поставщиками для интернет-магазинов. В нашей команде 10 разработчиков, специализирующихся на Laravel, Vue.js и высоконагруженных системах. Мы гарантируем, что синхронизация будет работать стабильно, а в случае сбоев — оперативно восстановим. Свяжитесь с нами для аудита вашего проекта — оценим текущую ситуацию и предложим оптимальное решение.
Ориентировочные сроки
| Этап | Срок |
|---|---|
| Полная синхронизация по расписанию | 2 рабочих дня |
| Дельта-синхронизация + realtime-проверка | 3–4 рабочих дня |
| Webhook-интеграция (если поддерживается) | +1 день |
Получите консультацию по выбору стратегии синхронизации и узнайте, как автоматизация может сократить возвраты и повысить лояльность клиентов. Мы готовы помочь на каждом этапе — от анализа до поддержки.







