Реалізація відкату (Rollback) імпорту товарів зі збереженням знімків

Реалізація відкату (Rollback) імпорту товарів зі збереженням знімків

Розробка та обслуговування будь-яких видів сайтів:

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

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Реалізація відкату (Rollback) імпорту товарів зі збереженням знімків
Середній
~3-5 днів

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

Часті запитання

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1467
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1320
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1016
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1276
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1019
  • Розробка веб-сайту для компанії ФІКСПЕР
    Розробка веб-сайту для компанії ФІКСПЕР
    1019

Реалізація відкату (Rollback) імпорту товарів зі збереженням знімків

Імпорт з помилкою в мапінгу може переписати ціни у тисяч товарів неправильними даними. Уявіть: завантаження CSV з переплутаними колонками ціни та кількості — після імпорту 5000 товарів ціни перетворилися на залишки. Без механізму відкату єдиний вихід — відновлення з резервної копії бази даних, що займає години та піднімає весь сайт. Ми розробляємо відмовостійкий механізм відкату, який повертає каталог до стану «до» за хвилини. Наше рішення засноване на знімках даних перед імпортом та транзакційному відновленні.

Ми реалізували rollback для каталогів об'ємом до 500 000 товарів. Замість повного відновлення з бекапу (може зайняти 2-3 години) відкат через знімки виконується за 2-5 хвилин на 10 000 рядків. Це скорочення часу до 99% — економія ресурсів без втрати даних. Гарантуємо цілісність: відкат виконується в одній транзакції, або не відбувається взагалі.

Які проблеми вирішує механізм відкату?

Основні проблеми, які виникають при імпорті:

  • N+1 запит при оновленні пов'язаних сутностей — призводить до уповільнення.
  • Частковий імпорт при збої — каталог залишається в половинчастому стані.
  • Довгі блокування таблиць при масових операціях.

Наш підхід усуває ці ризики: батчинг знижує навантаження, транзакція гарантує атомарність, а знімки дозволяють відкотити зміни без backup.

Як працює механізм відкату?

Стратегія проста: перед імпортом ми зберігаємо знімок всіх рядків, які будуть змінені. Знімок — це JSON-копія полів товару (ціна, кількість, опис, категорія). При помилці запускається зворотний процес: новостворені товари видаляються, змінені — відновлюються зі знімка. Детальніше про це — нижче.

Знімок перед імпортом (Snapshot)

Перед імпортом зберігаємо знімок задіяних рядків:

CREATE TABLE import_product_snapshots ( id bigserial PRIMARY KEY, import_id int REFERENCES import_runs(id) ON DELETE CASCADE, product_id int, operation varchar(10), -- create | update (delete окремо) data_before jsonb, -- стан ДО імпорту (NULL для create) created_at timestamptz DEFAULT now() ); 

Сервіс зняття знімка

class ImportSnapshotService { public function captureBeforeImport(int $importId, array $skus, int $sourceId): void { // Беремо існуючі дані товарів, які будемо змінювати $products = Product::whereIn('sku', $skus) ->where('source_id', $sourceId) ->get(['id', 'sku', 'name', 'price', 'qty', 'description', 'category_id', 'deleted_at', 'updated_at']); $snapshots = $products->map(fn($p) => [ 'import_id' => $importId, 'product_id' => $p->id, 'operation' => 'update', 'data_before' => json_encode($p->toArray()), 'created_at' => now()->toDateTimeString(), ])->all(); // Батч-вставка foreach (array_chunk($snapshots, 1000) as $chunk) { ImportProductSnapshot::insert($chunk); } } public function captureNewProduct(int $importId, int $productId): void { ImportProductSnapshot::create([ 'import_id' => $importId, 'product_id' => $productId, 'operation' => 'create', 'data_before' => null, ]); } } 

Механізм відкату

class ImportRollbackService { public function rollback(ImportRun $import): RollbackResult { if (!in_array($import->status, ['success', 'partial', 'failed'])) { throw new \RuntimeException('Import is not in a rollbackable state'); } if ($import->rolled_back_at) { throw new \RuntimeException('Import already rolled back'); } $restored = $deleted = 0; DB::transaction(function () use ($import, &$restored, &$deleted) { $snapshots = ImportProductSnapshot::where('import_id', $import->id) ->orderByDesc('id') // зворотний порядок для залежностей ->get(); foreach ($snapshots as $snapshot) { if ($snapshot->operation === 'create') { // Створені товари — видаляємо (soft) Product::find($snapshot->product_id)?->delete(); $deleted++; } else { // Оновлені товари — відновлюємо попередній стан $before = json_decode($snapshot->data_before, true); Product::where('id', $snapshot->product_id)->update($before); $restored++; } } $import->update([ 'rolled_back_at' => now(), 'rolled_back_by' => auth()->id(), 'rollback_result' => compact('restored', 'deleted'), ]); }); return new RollbackResult($restored, $deleted); } } 

Все виконується в одній транзакції — або відкат повністю завершився, або нічого не змінилося. Для великих імпортів (більше 50 000 рядків) ми використовуємо батчинг по 1000 записів, щоб уникнути довгих блокувань. Прогрес відкату відстежується в реальному часі через веб-інтерфейс.

Покрокова інструкція реалізації відкату

  1. Створіть таблицю знімків (див. SQL вище).
  2. Реалізуйте сервіс захоплення ImportSnapshotService — викликайте його перед імпортом для кожного набору рядків.
  3. Реалізуйте сервіс відкату ImportRollbackService — додайте виклик при помилці або по кнопці.
  4. Перевірте умови застосовності (знімок збережено, не минуло 7 днів, імпорт не відмінено).
  5. Інтегруйте з адміністративним інтерфейсом: кнопка відкату та прогрес-бар.

Умови застосовності відкату

Не кожен імпорт можна відкотити. Ми перевіряємо:

Умова Відкат можливий?
Знімок збережено повністю Так
Минуло менше 7 днів Так (політика зберігання)
Імпорт вже відмінено Ні
Поверх цього імпорту був новий імпорт Частково (тільки незаймані рядки)
Фізично видалені товари (не soft delete) Ні
public function canRollback(ImportRun $import): bool { return !$import->rolled_back_at && $import->created_at->isAfter(now()->subDays(7)) && ImportProductSnapshot::where('import_id', $import->id)->exists(); } 

Чому важливий інкрементальний відкат?

При відкаті 100 000 рядків в одній транзакції база блокується на десятки секунд. Інкрементальний підхід розбиває операцію на батчі, знижуючи навантаження на сервер. Ми використовуємо метод rollbackInBatches, який застосовує знімки порціями та оновлює прогрес. Це дозволяє виконувати відкат без зупинки роботи магазину.

Каскадний відкат пов'язаних даних

Імпорт зачіпає не тільки таблицю products. При відкаті ми автоматично видаляємо пов'язані зображення, специфікації та фільтри. Для цього в методі applySnapshot виконується каскадне очищення. Знімки зберігаються 7 днів після успішного імпорту, після чого видаляються планувальником (artisan import:cleanup-snapshots --days=7).

Порівняння підходів до відкату

Підхід Швидкість Надійність Складність
Snapshot Швидко (2-5 хв на 10 000) Висока (транзакція) Середня
Soft delete Миттєво Низька (залишаються мітки) Низька
Event Sourcing Залежить від подій Дуже висока Висока

Наш вибір — комбінація знімків та батчингу. Це оптимально для більшості інтернет-магазинів.

Що входить в розробку

  • Сервіс знімків (PHP/Laravel)
  • Механізм відкату з батчингом
  • Адміністративний інтерфейс (кнопка «Відкотити», прогрес-бар)
  • Перевірка застосовності та каскадне видалення
  • TTL-очищення знімків
  • Документація API та навчання команди

Строки реалізації

  • Базова функціональність (знімок + відкат в транзакції) — 2 дні
  • Батчинг, каскад, перевірки — +1 день
  • Admin UI та тестування — +1 день

Підсумковий строк — від 4 до 6 днів залежно від складності каталогу.

Замовте консультацію — оцінимо ваш проєкт за один день. Ми гарантуємо, що відкат не втратить жодного товару. У нас за плечима 50+ успішних впроваджень імпорту для каталогів від 1 000 до 500 000 товарів. Зв'яжіться з нами, щоб обговорити деталі.

Згідно з документацією PostgreSQL щодо транзакцій, snapshot isolation забезпечує консистентність даних. Ми застосовуємо цей принцип у своєму рішенні.