Operacja trwająca kilka sekund może utrzymywać otwarte żądanie HTTP, zużywać zasoby serwera WWW i pozostawiać użytkownika w niepewności, jeśli połączenie zostanie przerwane. Procesy działające w tle w PHP pozwalają przyjąć zadanie i wykonać je poza cyklem życia tego żądania. Aby takie rozwiązanie było użyteczne, samo dodanie kolejki nie wystarczy: trzeba określić, co otrzymuje użytkownik, jak sprawdza status i co dzieje się w razie przerwania.
Rozpoznaj, które operacje powinny być wykonywane w tle

Warto oceniać wpływ operacji, zamiast stosować regułę opartą wyłącznie na jej czasie trwania. Zadanie może się nadawać do takiego przetwarzania, jeśli jego czas wykonania jest zmienny, wymaga oczekiwania na system zewnętrzny lub obejmuje dużą liczbę elementów. Przykłady to generowanie obszernego raportu, import pliku, przekształcanie dokumentów lub synchronizowanie danych z API.
Jeśli jednak użytkownik potrzebuje natychmiastowej decyzji, aby móc kontynuować — na przykład sprawdzenia istotnych danych przed ich zapisaniem — lepiej może być pozostawić tę część w żądaniu i przenieść do osobnego procesu wyłącznie późniejsze zadania. Są też długotrwałe zadania, które ze względu na wymagania biznesowe muszą zwracać odpowiedź synchronicznie. Architektura powinna odpowiadać potrzebom przepływu, a nie zmieniać każdej operacji w zadanie asynchroniczne.
Zanim zmienisz projekt, ustal, ile trwa operacja, która jej część pochłania ten czas i co się dzieje w razie błędu. Kolejka sama w sobie nie naprawi nieefektywnych zapytań, źle skonfigurowanych limitów ani niestabilnych zależności zewnętrznych; może jedynie przenieść te problemy na workery działające w tle.
Zwracaj informację o przyjęciu zadania, a nie zmyślony wynik
Gdy zadanie zostaje przyjęte do późniejszego wykonania, odpowiedź aplikacji powinna jasno odróżniać stan przyjęte od zakończone. Może zwracać identyfikator zadania i informację, że przetwarzanie oczekuje na rozpoczęcie. Nie powinna przedstawiać jako gotowego wyniku, który jeszcze nie istnieje.
Szacowanie czasu jest właściwe tylko wtedy, gdy dostępne są wystarczające dane do obliczenia go i zakomunikowania niepewności. W wielu systemach uczciwiej jest pokazać status „w kolejce” lub „przetwarzanie” niż obiecywać godzinę zakończenia. Jeśli zadanie może zostać szybko ukończone, interfejs nadal może sprawdzać jego status i wyświetlić wynik, gdy będzie dostępny, bez blokowania pierwotnego żądania.
Określ również, co się dzieje, gdy nie uda się wysłać zadania do kolejki: aplikacja nie powinna potwierdzać jego przyjęcia, jeśli nie może wiarygodnie zarejestrować zadania. Konkretne rozwiązanie zależy od architektury, ale odpowiedź i utrwalony status muszą być ze sobą spójne.
Określ statusy i prawidłowe przejścia
Niewielki, jasno zdefiniowany cykl życia ułatwia korzystanie z systemu i jego obsługę. Podstawowy zestaw może obejmować statusy pending, running, cancel_requested, completed, failed i cancelled. Nazwy mogą się różnić; przejścia muszą być jednak prawidłowe i możliwe do zweryfikowania, a nie stanowić dowolnej kombinacji statusów.
- Standardowe przejścia:
pending → running, a następnie zrunningdocompletedlubfailed. - Anulowanie przed rozpoczęciem:
pending → cancelled, jeśli potwierdzono, że worker nie rozpoczął jeszcze zadania. - Anulowanie podczas wykonywania:
running → cancel_requested. Z tego statusu zadanie przechodzi docancelled, jeśli zostanie bezpiecznie zatrzymane; może przejść docompleted, jeśli zakończyło się przed obsłużeniem żądania, albo dofailed, jeśli wystąpił błąd. - Statusy końcowe:
completed,failedicancellednie powinny wracać do statusów aktywnych. Jeśli ponowne wykonanie zadania jest dozwolone, utwórz nowe wykonanie albo jawnie zdefiniuj inny cykl.
System powinien blokować niedozwolone przejścia i rejestrować czas każdej zmiany. Jeśli worker zostanie przerwany, pozostawiając zadanie ze statusem running, nie oznaczaj go automatycznie jako zakończone. Zasady odzyskiwania mogą przywracać status pending, gdy bezpieczne wznowienie jest możliwe, albo oznaczać zadanie jako failed do sprawdzenia. Decyzja zależy od tego, czy można wznowić pracę bez powielania skutków. Koordynowanie ponownych prób i idempotencja wymagają osobnych decyzji; nie należy ich mylić z widocznym modelem statusów.
Informuj o postępie, wyniku i błędach
Postęp powinien opierać się na mierzalnych etapach. Jeśli nie da się obliczyć rzeczywistego procentu, lepiej poinformować o bieżącej fazie („weryfikowanie danych”, „generowanie raportu”) albo pozostawić status „w toku”. Procent, który pozostaje bez zmian lub cofa się bez wyjaśnienia, obniża zaufanie.
Po zakończeniu udostępnij wynik biznesowy: na przykład podsumowanie przetworzonych elementów lub odnośnik do wygenerowanego zasobu, z uwzględnieniem uprawnień i dostępności. Status zadania nie musi przechowywać całego wyniku. Może zawierać odwołanie do danych zarządzanych przez domenę aplikacji.
W razie niepowodzenia system powinien wyświetlić komunikat, który pomoże zdecydować o następnym kroku, na przykład poprawieniu pliku lub ponowieniu próby, jeśli jest to właściwe. Osobno rejestruj informacje o błędzie technicznym niezbędne do diagnostyki, ograniczając do nich dostęp. Nie ujawniaj śladów stosu, danych uwierzytelniających, wewnętrznych ścieżek ani danych wrażliwych w interfejsie lub publicznym API.
Traktuj anulowanie jako żądanie z ograniczeniami
Anulowanie zadania nie zawsze oznacza, że można je natychmiast zatrzymać. Worker może wykonywać wywołanie zewnętrzne, zapisywać dane lub znajdować się w fazie, której bezpiecznie nie da się przerwać. Dlatego interfejs powinien odróżniać cancel_requested od cancelled: pierwszy status oznacza, że żądanie zostało odebrane; drugi — że system potwierdził zatrzymanie.
Implementacja może sprawdzać sygnał anulowania w bezpiecznych punktach i nie rozpoczynać kolejnych etapów. Jeśli skutek został już zatwierdzony w systemie zewnętrznym, nie należy twierdzić, że został cofnięty. Wyjaśnij użytkownikowi, jakiego wyniku może się spodziewać, i rejestruj, kto zażądał anulowania, jeśli informacja ta jest istotna z punktu widzenia audytu.
Oddziel rejestr zadania od wyniku biznesowego
Rejestr zadania służy do koordynowania wykonania i sprawdzania jego statusu: może zawierać identyfikator, status, daty, osobę zgłaszającą i odwołania diagnostyczne. Wynik biznesowy — na przykład raport lub zaimportowane rekordy — należy do modelu danych reprezentującego ten wynik.
Rozdzielenie tych elementów zapobiega temu, by zadanie zawierające tymczasowe informacje stało się jedynym źródłem danych biznesowych. Umożliwia też określenie zasad retencji: jak długo przechowywać status, kiedy usuwać plik i jakie informacje należy zachować ze względów operacyjnych lub prawnych. Stare statusy nie powinny gromadzić się bez zasad czyszczenia.
Zabezpiecz sprawdzanie statusu i ogranicz zużycie zasobów
Sprawdzanie zadania wymaga autoryzacji tak samo jak sprawdzanie dowolnego innego zasobu. Identyfikator nie zastępuje kontroli dostępu: zweryfikuj, czy osoba lub system zgłaszający żądanie może zobaczyć dane zadanie i jego wynik. Ogranicz również częstotliwość i liczbę zapytań, aby uniknąć nadmiernego odpytywania, a w przypadkach użycia, które nie wymagają ciągłych aktualizacji, rozważ powiadomienia.
Wykonywanie zadań powinno podlegać limitom współbieżności i zasobów odpowiednim dla danego rodzaju pracy. Zbyt wielu workerów może przeciążyć bazę danych, usługi zewnętrzne lub pamięć masową; zbyt mało może powodować gromadzenie się zadań i opóźniać wyniki. Monitoruj liczbę oczekujących zadań, ich wiek i czas wykonania, a także błędy. Te sygnały pomagają odróżnić wolną zależność od problemu z wydajnością.
Przetestuj cały cykl przed wdrożeniem
Testy akceptacyjne powinny obejmować widoczne zachowanie i utrwalanie danych, a nie tylko sprawdzać, czy worker wywołuje funkcję. Sprawdź co najmniej następujące scenariusze:
- Żądanie tworzy zadanie i zwraca odwołanie do niego, nie twierdząc, że zostało już zakończone.
- Zakończone zadanie wyświetla status końcowy i umożliwia dostęp do wyniku z odpowiednimi uprawnieniami.
- W razie niepowodzenia system wyświetla bezpieczny komunikat, a upoważniony zespół ma dostęp do informacji diagnostycznych.
- Porzucone lub przerwane zadanie nie pozostaje bez końca w stanie „w toku”; istnieje operacyjny sposób wykrywania go i obsługi.
- Żądanie anulowania uwzględnia bezpieczne fazy i nie obiecuje cofnięcia skutków, które już wystąpiły.
W istniejącym systemie wprowadź zmianę dla ograniczonej operacji i sprawdź również działanie systemu, gdy kolejka jest opóźniona lub niedostępna. Aplikacja musi jasno reagować w takich przypadkach: informować, że nie mogła przyjąć zadania, oferować bezpieczną alternatywę lub umożliwiać użytkownikowi ponowienie próby. Decyzja zależy od wpływu operacji i gwarancji, jakie firma może zapewnić.
Lista kontrolna dotycząca wprowadzania kolejki w istniejącym systemie

Przed włączeniem przetwarzania w tle omów poniższe kwestie z zespołami odpowiedzialnymi za aplikację i jej działanie:
- Zakres: wybrano konkretną operację i określono, która jej część pozostaje synchroniczna, a która jest wykonywana w tle.
- Trwałość danych: przyjęcie zadania i jego status są zapisywane w spójny sposób; istnieją zasady dotyczące przerwań, odzyskiwania i zmian statusu.
- Umowa z użytkownikiem: początkowa odpowiedź odróżnia przyjęcie zadania od jego zakończenia, a interfejs wyjaśnia, jak sprawdzać postęp, wynik i błędy.
- Uprawnienia i dane: sprawdzenie zadania lub jego wyniku wymaga autoryzacji; ograniczono ilość przechowywanych danych i dostęp do informacji diagnostycznych.
- Zasoby: ustalono limity współbieżności, czasu wykonania, pamięci i częstotliwości zapytań odpowiednie dla operacji i jej zależności.
- Obserwowalność: można wykrywać narastające zaległości, stare zadania w toku, błędy i nietypowe czasy wykonania bez umieszczania sekretów w logach.
- Retencja: ustalono, jak długo przechowywać statusy, wyniki, pliki i dane diagnostyczne oraz jak usuwać je w kontrolowany sposób.
- Testy i obsługa: przetestowano scenariusze zakończenia, błędu, anulowania i przerwania, a zespół wie, co robić, gdy kolejka nie przyjmuje zadań lub działa z opóźnieniem.
Wdrożenie kodu nie oznacza natychmiastowego włączenia wszystkich przepływów: możesz stopniowo wprowadzać nową ścieżkę wykonania i sprawdzać jej wskaźniki, zanim rozszerzysz jej użycie. Zachowaj odpowiednią alternatywę operacyjną na wypadek niedostępności kolejki lub jej workerów; nie potwierdzaj zadań, których system nie zdołał zarejestrować.



