Otwarte na nowe projekty +48 887 255 528 · kontakt[at]kosari.pl

Test na kopii a Kalendarz Google: czego nie cofnie żaden rollback

Rollback nie cofa API: test w transakcji cofa bazę, ale nie wydarzenia w Kalendarzu Google, maile ani webhooki. Jak testować na produkcji bez śladów.

9 min czytania Systemy i aplikacje
Test na kopii a Kalendarz Google: czego nie cofnie żaden rollback

Test „w transakcji” brzmi bezpiecznie: na końcu ROLLBACK i baza wraca do stanu sprzed testu co do wiersza. Tyle że rollback nie cofa API. Jeśli testowany kod rozmawia z Kalendarzem Google, wysyła maile albo webhooki, te zmiany zostają tam, dokąd poszły – a po kilku dniach potrafią wrócić do systemu tylnymi drzwiami, na przykład jako zajęte terminy. Pokazujemy, dlaczego „test w transakcji” to tylko połowa zabezpieczenia i jak zrobić test na żywym systemie, który naprawdę nie zostawia śladów.

Kontekst: system rezerwacji spięty z Kalendarzem Google

Przykład: studio tańca, w którym rezerwacje lekcji, pakiety, instruktorki i płatności obsługuje rozbudowany system na WordPressie. Każda lekcja zapisana w systemie trafia jako wydarzenie do Kalendarza Google. Działa to też w drugą stronę: osobne zadanie cykliczne co jakiś czas czyta kalendarz i zaznacza zajęte godziny, żeby nikt nie zarezerwował terminu, który instruktorka ma już zajęty prywatnie.

Stawka jest prosta. Kalendarz to miejsce, w którym właścicielka planuje swój dzień i swój zarobek. Każda godzina oznaczona jako zajęta, choć w rzeczywistości wolna, to termin, którego nikt nie może kupić.

Jak wygląda pułapka: test, który „niczego nie zmienia”

Zmianę w logice zapisów najlepiej sprawdzić na prawdziwych danych, a nie na wymyślonych. Na prawdziwych danych wychodzą długie nazwiska, nietypowe pakiety i przypadki, o których nikt nie pomyślał przy projektowaniu. Dlatego testy idą często na żywej instalacji, według popularnego wzorca:

START TRANSACTION;
-- test: tworzenie zapisu, lekcji, rezerwacji, sprawdzenie wyników
ROLLBACK;

W bazie wszystko działa tak, jak ma. Po wycofaniu transakcji liczba wierszy w tabelach jest identyczna jak przed testem. Wygląda na test czysty.

Nie jest. Funkcja tworząca lekcję w ramach swojej pracy wysyła też wydarzenie do Kalendarza Google. Takie wywołanie idzie przez internet do serwerów Google i tam zostaje. ROLLBACK nie ma o nim pojęcia. W kalendarzu zostają prawdziwe wydarzenia dla lekcji, które w bazie przestały istnieć sekundę po utworzeniu.

Jak test w transakcji zostawił duchy w kalendarzuTest + ROLLBACKbaza cofniętaco do wierszaGoogle: wydarzeniawywołania APIposzły i zostałySynchronizacjawydarzenia wracająjako zajęte slotyPo kilku dniachterminy znikająz ofertyBaza była czysta przez cały czas. Bałagan powstał wyłącznie poza nią.
Rollback zadziałał bez zarzutu – tylko że dotyczył jednego z kilku miejsc, do których kod zapisywał dane.

To nie koniec. Zadanie synchronizacji robi dokładnie to, do czego zostało napisane: czyta kalendarz, znajduje w nim wydarzenia i oznacza odpowiadające im godziny jako zajęte. Duchy z testu zamieniają się w realnie zablokowane terminy w systemie rezerwacji – błąd, który zaczął się w teście, wraca do bazy tylnymi drzwiami.

Diagnoza: jak rozpoznać duchy z testu

Najpierw odruchowo: błąd w logice duplikatów

Objaw brzmi „zdublowane wpisy”, więc pierwszy odruch to szukanie miejsca, w którym system wysyła to samo wydarzenie dwa razy. Jeśli kod synchronizacji jest w porządku, a dla podejrzanych wydarzeń w bazie nie ma żadnego zapisu, który mógłby zostać zdublowany, to nie jest dubel.

Trop: podpis w opisie wydarzenia

Każde wydarzenie, które system wysyła do Google, ma w opisie znacznik systemu z datą i godziną utworzenia. Jeśli podejrzane wpisy mają znacznik z dnia testów, z godzinami pokrywającymi się z przebiegiem testu co do minuty, wiadomo, skąd się wzięły.

Druga pułapka: „przecież blokowałem sieć”

Standardowy filtr WordPressa pre_http_request przechwytuje zapytania HTTP i zwraca błąd zamiast je wysyłać. Wydaje się, że to wystarczy. Nie wystarcza, z dwóch powodów:

  • Biblioteka klienta Google nie używa funkcji HTTP WordPressa. Chodzi przez własnego klienta (Guzzle) i cURL, więc filtr pre_http_request w ogóle jej nie widzi.
  • Inna wtyczka na tej samej stronie potrafi podmienić Twój błąd. Wisi na tym samym filtrze z późniejszym priorytetem i zwraca własną odpowiedź. Blokada istnieje w kodzie, ale nie działa.

Transakcja bazy danych cofa tylko to, co zapisano w tej bazie. Wszystko, co kod wysłał na zewnątrz – wydarzenie w kalendarzu, mail, SMS, webhook, płatność, plik na dysku – zostaje tam, dokąd poszło. A blokada sieci na poziomie WordPressa nie łapie bibliotek, które mają własnego klienta HTTP.

Co cofa ROLLBACK, a czego nieKod testowanyBaza danychROLLBACK cofaKalendarz GooglezostajeMaile i SMSzostająWebhooki, płatnościzostająPliki, zmiany tabelzostają
Transakcja obejmuje jedno pudełko z sześciu. Pozostałe trzeba zablokować osobno, zanim test w ogóle ruszy.

Jeszcze jedna mina, o której mało kto pamięta: w MySQL i MariaDB polecenia zmieniające strukturę tabel (ALTER TABLE, CREATE TABLE) wykonują niejawny COMMIT. Jeśli testowany kod zrobi coś takiego w środku transakcji, wszystko, co było przed nim, zostaje zatwierdzone na stałe – a końcowy ROLLBACK nic nie zgłosi.

Sprzątanie: najpierw dowód, potem kasowanie

Kusi, żeby po prostu wejść w kalendarz i usunąć „te dziwne wpisy”. Nie rób tego ręcznie: kalendarz to narzędzie pracy, a jedno pomylone kliknięcie kasuje prawdziwą lekcję. Bezpieczna kolejność:

  1. Inwentaryzacja wszystkich kalendarzy podpiętych do systemu, nie tylko tego, w którym zauważono problem.
  2. Walidacja każdej pozycji osobno, trzema warunkami naraz: znacznik systemu z dnia testu, zero lekcji w bazie powiązanych z tym wydarzeniem, slot bez żadnej rezerwacji. Wydarzenie, które nie spełniało wszystkich trzech, zostawało nietknięte.
  3. Kopia zapasowa do pliku JSON każdego wydarzenia i slotu przed usunięciem.
  4. Usunięcie wydarzeń i slotów przez API, tą samą drogą, którą system je tworzy.
  5. Ponowna inwentaryzacja. Zero duchów, kalendarz zgadza się z systemem jeden do jednego.

Jeśli Twoja firma też ma system, który rozmawia z kalendarzem, pocztą albo bramką płatności, i nie masz pewności, co dzieje się przy każdej zmianie, zobacz, jak podchodzimy do automatyzacji i integracji między systemami. Zaczynamy zawsze od mapy: skąd dane wychodzą i dokąd trafiają.

Rozwiązanie: test, który odmawia startu, jeśli nie jest szczelny

Samo posprzątanie niczego nie zmienia – następny test zrobi to samo. Dlatego przy systemach z integracjami każdy test na żywej instalacji puszczamy wyłącznie przez narzędzie testowe, które robi pięć rzeczy:

  1. Blokuje HTTP z najwyższym możliwym priorytetem. Filtr zawieszony na PHP_INT_MAX wykonuje się jako ostatni, więc żadna inna wtyczka nie podmieni już jego wyniku.
  2. Odcina Google u źródła. Skoro filtr HTTP nie łapie biblioteki Google, test podmienia jej konfigurację: bez danych uwierzytelniających funkcja tworząca klienta Google zwraca błąd, a synchronizacja uznaje kalendarz za wyłączony.
  3. Przechwytuje maile filtrem pre_wp_mail. Nic nie wychodzi, a lista „wysłanych” wiadomości jest dostępna do sprawdzenia w teście.
  4. Sprawdza blokady, zanim cokolwiek ruszy. Jeśli klient Google wciąż daje się utworzyć albo próbne zapytanie HTTP przechodzi, narzędzie kończy pracę z błędem i test się nie odpala.
  5. Porównuje odcisk bazy przed i po. Dla kilkudziesięciu tabel liczy wiersze, najwyższe ID i datę ostatniej zmiany. Każdy rozjazd po ROLLBACK kończy się błędem, a nie cichym „OK”.

Szkielet blokad wygląda tak (uproszczony):

// Maile: przechwyć, nie wysyłaj
add_filter('pre_wp_mail', function ($r, $a) {
    $GLOBALS['TEST']['maile'][] = $a;
    return true;
}, PHP_INT_MAX, 2);

// HTTP przez WordPressa: blokada jako OSTATNI filtr
add_filter('pre_http_request', function ($r, $args, $url) {
    $GLOBALS['TEST']['http'][] = $url;
    return new WP_Error('test', 'HTTP zablokowane w teście');
}, PHP_INT_MAX, 3);

// Kontrola PRZED testem: blokada ma działać naprawdę
if (!is_wp_error(wp_remote_get('https://example.com/'))) {
    echo "STOP: HTTP nie jest zablokowane\n";
    exit(1);
}
Przebieg testu, który nie zostawia śladówBlokadyHTTP, Google, mailKontrolanie trzyma = STOPOdcisk przedTest+ ROLLBACKOdcisk poPorównanierozjazd = błądKażdy krok może zatrzymać test. Żaden nie może go „przepuścić na słowo”.
Narzędzie najpierw udowadnia, że wyjścia są zamknięte, a dopiero potem pozwala testowi cokolwiek zrobić.

Jak sprawdziliśmy, że narzędzie naprawdę łapie bałagan

Bramka, której nigdy nie widziałeś odmawiającej, nie jest bramką. Dlatego zanim zaufaliśmy narzędziu, puściliśmy przez nie test celowo brudny – taki, który w środku zmienia strukturę tabeli, czyli wywołuje niejawny COMMIT. Porównanie odcisków wykryło zmienione wiersze i narzędzie zakończyło się błędem. Dopiero wtedy wiedzieliśmy, że „zielony” wynik coś znaczy.

Efekt

Testy na żywej instalacji dalej mają sens, bo prawdziwe dane łapią błędy, których dane testowe nie złapią. Różnica polega na tym, że każdy taki test kończy się dowodem czystości – listą zablokowanych zapytań, przechwyconych maili i porównaniem bazy – a nie naszym przekonaniem, że „przecież był w transakcji”.

Jak sprawdzić u siebie: checklista przed testem na produkcji

  • Wypisz, co testowany kod robi poza bazą: kalendarze, maile, SMS, webhooki, płatności, faktury, pliki, kolejki zadań.
  • Sprawdź, czy integracje używają funkcji HTTP Twojej platformy, czy własnych bibliotek (SDK Google, Stripe, AWS). Te drugie trzeba odciąć u źródła, np. konfiguracją lub brakiem kluczy.
  • Zawieś blokady z najwyższym priorytetem i sprawdź, że działają, zanim test ruszy. Kontrola ma kończyć się błędem, nie ostrzeżeniem.
  • Upewnij się, że test nie zmienia struktury tabel w środku transakcji – w MySQL to niejawny COMMIT.
  • Porównaj stan przed i po: liczby wierszy, najwyższe ID, daty zmian, nowe pliki w katalogu uploadów.
  • Po teście zajrzyj tam, dokąd kod mógł pisać: kalendarz, skrzynka nadawcza, panel bramki płatności.

Najważniejsze pytanie przed testem

„Test w transakcji” brzmi bezpiecznie i właśnie dlatego jest groźny – daje poczucie pełnej ochrony, a chroni jedno miejsce z wielu. Efekty uboczne wychodzą przez integracje. Dlatego przed każdym testem na żywym systemie zadajemy jedno pytanie: co ten kod robi poza bazą? I każdą odpowiedź zamieniamy w blokadę, która sama sprawdza, czy działa.

FAQ

Czy ROLLBACK w MySQL cofa wywołania API?

Nie. Rollback nie cofa API ani niczego innego poza zapisami w tej samej bazie danych. Wydarzenie wysłane do Kalendarza Google, mail czy webhook wychodzą z serwera natychmiast i transakcja nie ma nad nimi żadnej władzy.

Dlaczego pre_http_request nie zablokował Kalendarza Google?

Bo biblioteka klienta Google nie korzysta z funkcji HTTP WordPressa, tylko z własnego klienta (Guzzle) i cURL. Filtr pre_http_request działa wyłącznie dla zapytań wysyłanych przez wp_remote_get, wp_remote_post i pokrewne funkcje.

Skąd w Kalendarzu Google duplikaty wydarzeń z WordPressa?

Najczęściej z ponownej synchronizacji albo z testów, które utworzyły wydarzenia, a potem cofnęły tylko bazę. Pomaga znacznik systemu z datą w opisie każdego wydarzenia – po nim od razu widać, kiedy i skąd wpis powstał.

Czy da się w ogóle bezpiecznie testować na produkcji?

Da się, jeśli test jest szczelny na wszystkich wyjściach, a nie tylko na bazie, i jeśli sam sprawdza swoje blokady przed startem. Tam, gdzie to możliwe, lepiej i tak zacząć od kopii strony na osobnym środowisku z wyłączoną wysyłką.

Jak bezpiecznie usunąć zbędne wydarzenia z Kalendarza Google?

Najpierw inwentaryzacja i kopia zapasowa do pliku, potem usuwanie tylko tych pozycji, które spełniają wszystkie warunki naraz (np. znacznik testu i brak powiązanej lekcji). Na koniec druga inwentaryzacja, która potwierdza, że kalendarz zgadza się z systemem.

Inna wtyczka nadpisuje mój filtr. Co robić?

Zawieś swój filtr z priorytetem PHP_INT_MAX, żeby wykonał się jako ostatni, i zawsze sprawdź jego działanie realnym wywołaniem przed testem. Sama obecność add_filter w kodzie niczego nie dowodzi.

Masz system rezerwacji, sklep albo CRM spięty z kalendarzem, pocztą i płatnościami i chcesz go rozwijać bez strachu, że każda zmiana zostawi bałagan u klientów?

Budujemy i utrzymujemy takie systemy, a każdą zmianę testujemy tak, żeby po teście nie było śladu poza raportem. Przy stronach na WordPressie pomaga też stała opieka WordPress.

Napisz do nas – opisz swój system, a powiemy, gdzie są jego wyjścia

Grzegorz Rówiński · Kosari

Buduję strony, sklepy i platformy kursowe, automatyzuję procesy i wdrażam AI w firmach. Ten wpis powstał z realnego wdrożenia, nie z teorii.

Napisz do mnie →

Przeczytaj też

Masz podobny problem i nie chcesz go debugować sam?

Napisz krótko co się dzieje. Odpowiadamy konkretnie, bez zobowiązań - powiemy z czego to najpewniej wynika i ile kosztuje naprawa.

Napisz do nas

Wolisz porozmawiać? Zadzwoń: +48 887 255 528

Zadzwoń +48 887 255 528