Реализация синхронизации остатков с дропшиппинг-поставщиком
Сталкивались с ситуацией, когда покупатель оформляет заказ, а поставщик сообщает: товара нет в наличии? Это приводит к возвратам, недовольству клиентов и потере репутации. Особенно болезненно, когда на сайте отображается наличие, а реальный остаток уже нулевой. Разница между витриной и реальностью может составлять часы, а для популярных позиций — минуты. По статистике, до 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 день |
Получите консультацию по выбору стратегии синхронизации и узнайте, как автоматизация может сократить возвраты и повысить лояльность клиентов. Мы готовы помочь на каждом этапе — от анализа до поддержки.







