Przejdź do treści
DedicatedPHP Kontakt

Jak bezpiecznie wstrzymywać i wznawiać automatyzację w PHP

Projektuj bezpieczne wstrzymania w przepływach PHP: zapisuj punkt wznowienia, kontroluj, kto podejmuje decyzję, i unikaj ponownego wykonywania efektów po wznowieniu.

Schemat przepływu PHP wstrzymanego w celu uzyskania interwencji i wznowionego z trwałego stanu

Automatyzacja może dotrzeć do punktu, w którym nie powinna działać dalej bez decyzji, danych lub sprawdzenia. Może na przykład wymagać zatwierdzenia przed potwierdzeniem wrażliwej operacji albo czekać na informacje, które może przekazać tylko człowiek. W takich przypadkach system powinien zachować stan umożliwiający wznowienie i wyjaśnić, czego brakuje, zamiast po prostu zatrzymać bieżące wykonanie.

Projektowanie sposobu wstrzymywania i wznawiania automatyzacji w PHP wymaga oddzielenia stanu procesu od wykonywania pracy. Wstrzymanie powinno być celowe, trwałe i możliwe do audytu; wznowienie powinno sprawdzać, czy proces nadal jest prawidłowy i czy zastosowane już efekty nie zostaną powtórzone. To coś innego niż projektowanie kolejki do weryfikacji: tutaj najważniejszy jest cykl życia przepływu i jego bezpieczna kontynuacja.

Odróżnij wstrzymanie od oczekiwania lub błędu

Odróżnij wstrzymanie od oczekiwania lub błędu — guía visual de DedicatedPHP

Nie każdy proces, który nie posuwa się naprzód, jest wstrzymany. Wywołanie API, na które nie nadeszła jeszcze odpowiedź, oznacza oczekiwanie na zewnętrzną odpowiedź. Błąd sieci może uzasadniać ponowną próbę. Wyjątek, po którym nie można odzyskać działania, może zakończyć proces jako nieudany. Celowe wstrzymanie oznacza natomiast, że przepływ dotarł do znanej granicy i wymaga jawnego warunku, aby kontynuować lub zakończyć działanie.

Używanie odrębnego stanu dla każdej sytuacji zapobiega błędnym decyzjom operacyjnym. Ponowienie działania oczekującego na zatwierdzenie może spowodować niepotrzebne powtórzenie żądania; potraktowanie uzasadnionego wstrzymania jako błędu może uruchomić alerty lub procedury odzyskiwania, które nie mają zastosowania. Zdefiniuj co najmniej osobne stany dla wykonywania, oczekiwania na zewnętrzną odpowiedź, wymaganej interwencji, zakończenia, anulowania i niepowodzenia. Dodaj termin ważności, jeśli reguły biznesowe wymagają, by wstrzymanie przestało być ważne po upływie określonego czasu.

Zanim dodasz wstrzymanie, określ, co je wywołuje i kto może je rozstrzygnąć. Oczekujące zadanie, które kończy się automatycznie po otrzymaniu odpowiedzi, nie zawsze wymaga interwencji człowieka. Może być ona konieczna w przypadku decyzji mającej wpływ na finanse, kwestie prawne, dostęp lub bezpieczeństwo. To rozróżnienie określa, kto może podjąć działanie, jakie dowody należy zachować i co się stanie, jeśli nikt nie odpowie.

Zapisuj stan i punkt wznowienia

Proces musi przetrwać zakończenie żądania PHP, restart workera i wdrożenie nowej wersji usługi. Zapisuj w trwałym magazynie stabilny identyfikator, bieżący stan, osiągnięty krok, przyczynę wstrzymania, odwołania do wymaganych danych oraz istotne znaczniki czasu. W razie potrzeby zapisuj też, kto wstrzymał lub rozstrzygnął proces, oraz podjętą decyzję.

Nie ograniczaj się do zapisania komunikatu w rodzaju „oczekuje na zatwierdzenie”. Nie wskazuje on, które wykonanie zostało zatrzymane, który krok należy kontynuować ani czy dane uległy zmianie. Zamiast tego uwzględnij wstrzymanie w modelu procesu i zapisz kontekst wystarczający do zweryfikowania wznowienia. W miarę możliwości zachowuj odwołania do informacji wrażliwych zamiast niepotrzebnie kopiować dane; stosuj kontrolę dostępu i zasady retencji odpowiednie do ich charakteru.

Zdefiniuj dozwolone przejścia i weryfikuj je po stronie serwera. Na przykład proces w stanie wymagającym interwencji może przejść do wykonywania, anulowania lub wygaśnięcia; proces zakończony nie powinien wrócić do wykonywania w wyniku zwykłego żądania. Funkcja PHP może weryfikować przejście, ale reguła musi być zabezpieczona również przed współbieżnością na poziomie bazy danych, a nie tylko interfejsu.

Oddziel rejestrowanie procesu od jego wykonywania

Zarejestrowanie, że proces ma być kontynuowany, i wykonanie jego kroków to powiązane, ale nieidentyczne operacje. Jeśli stan zostanie zaktualizowany, a proces zakończy się przed rozpoczęciem pracy, przepływ może utknąć. Jeśli praca rozpocznie się przed zapisaniem przejścia, ponowienie może wykonać ten sam krok. Zaprojektuj koordynację tak, aby trwały stan umożliwiał odzyskanie oczekującej pracy.

Typowym rozwiązaniem jest zapisanie przejścia i instrukcji kontynuacji w ramach jednej transakcji bazy danych, na przykład z użyciem wzorca transactional outbox. Osobny worker odczytuje tę instrukcję i wykonuje kolejny krok. Konkretne rozwiązanie zależy od architektury; najważniejsze jest, by system potrafił wykryć niewykonaną pracę i ją odzyskać, zamiast polegać na tym, że żądanie webowe pozostanie aktywne.

Efekty zewnętrzne wymagają dodatkowej uwagi. Lokalna transakcja nie może sama cofnąć wysłanej wiadomości e-mail, zrealizowanego obciążenia ani wywołania zaakceptowanego już przez inną usługę. Projektuj każdy krok z kluczem idempotencji, jeśli system docelowy na to pozwala, zapisuj wynik przed przejściem dalej i uwzględnij uzgadnianie lub kompensację, gdy operacji nie można bezpiecznie powtórzyć. Nie oznaczaj kroku jako zakończonego, dopóki nie poznasz jego wyniku.

Kontroluj wznawianie, anulowanie i wygaśnięcie

Operacja wznowienia powinna weryfikować aktualny stan, tożsamość i uprawnienia osoby zgłaszającej żądanie oraz spełnienie wymaganych warunków. Samo wyświetlenie przycisku uprawnionej osobie nie wystarczy: serwer musi ponownie zweryfikować wszystkie te elementy po otrzymaniu żądania. Jeśli decyzja wymaga uzasadnienia lub dodatkowych danych, zweryfikuj te informacje i zachowaj je jako część rozstrzygnięcia.

Traktuj również anulowanie i wygaśnięcie jako jawne przejścia, a nie usunięcie rekordu. Anulowanie powinno uniemożliwiać wykonanie kolejnych kroków i jasno wskazywać, czy istnieją wcześniejsze efekty, których nie da się cofnąć. Wygaśnięcie powinno określać, co stanie się dalej: proces zostanie zakończony, ponownie wymagana będzie interwencja czy sprawa zostanie przekazana do innego działania. Zachowanie zależy od reguł biznesowych i powinno być widoczne dla zespołu operacyjnego.

Powtarzające się żądania i wyścigi są czymś normalnym: użytkownik może kliknąć dwa razy albo dwóch uczestników może zadziałać niemal jednocześnie. Użyj aktualizacji warunkowej, blokady lub kontroli wersji, aby wygrało tylko jedno prawidłowe przejście. Drugie żądanie powinno otrzymać wynik zgodny z aktualnym stanem, bez ponownego wykonywania efektów. Zapisuj identyfikator operacji lub klucz idempotencji, by rozpoznawać powtórzenia.

Zadbaj, by wstrzymanie było zrozumiałe i możliwe do zweryfikowania

Widok operacyjny powinien wyjaśniać, dlaczego proces został zatrzymany, który krok pozostaje do wykonania, jakich informacji brakuje, kto może podjąć działanie i jakie są konsekwencje poszczególnych opcji. Unikaj niejednoznacznych przycisków i działań łączących zatwierdzanie, poprawianie danych oraz kontynuowanie procesu. Pokazuj tylko informacje niezbędne do podjęcia decyzji, z dostępem ograniczonym odpowiednio do roli. Historia przejść pozwala odróżnić uzasadnione oczekiwanie od zablokowanego lub błędnie skonfigurowanego procesu.

Przetestuj przepływ, uwzględniając przerwania przed każdym efektem zewnętrznym i po nim. Sprawdź, czy restart nie powoduje utraty wstrzymania, ponowne wznowienie nie dubluje działań, a anulowanie uniemożliwia wykonanie kolejnych kroków. Uwzględnij przypadki zmiany danych podczas wstrzymania, cofnięcia uprawnień, wygaśnięcia, spóźnionych odpowiedzi i dwóch równoczesnych żądań. Sprawdź też logi i alerty: powinny umożliwiać odnalezienie procesu i zrozumienie kolejnego kroku bez ujawniania sekretów.

Lista kontrolna pomagająca wybrać właściwe działanie

Lista kontrolna pomagająca wybrać właściwe działanie — guía visual de DedicatedPHP
  • Oczekiwanie: trwa oczekiwanie na zewnętrzną odpowiedź, a system może automatycznie kontynuować po jej otrzymaniu; limity czasu i odzyskiwanie są zdefiniowane.
  • Wstrzymanie w celu uzyskania interwencji: przed wykonaniem kolejnych kroków potrzebna jest jawna decyzja człowieka lub podane przez niego dane.
  • Ponowienie: wystąpił przejściowy błąd, a powtórzenie kroku jest bezpieczne lub chronione przez idempotencję.
  • Zakończenie: nie ma prawidłowej możliwości kontynuacji albo proces został ukończony, anulowany, wygasł lub zakończył się definitywnym niepowodzeniem.

Przed wdrożeniem przepływu potwierdź, że każde przejście jest autoryzowane, stan jest trwały, wcześniejsze efekty nie zostaną powtórzone, a zespół wie, jak rozstrzygnąć wstrzymanie. Jeśli nie potrafisz odpowiedzieć, co zostanie wznowione, na jakich danych i pod jakimi warunkami, proces nie ma jeszcze bezpiecznego punktu wznowienia.

Chcesz zastosować te pomysły w swoim projekcie?Omówmy Twoją platformę PHP.
Zobacz powiązaną usługę