Photo by Emile Perron on Unsplash
PHP (Hypertext Preprocessor) är ett skriptspråk med öppen källkod som utformades med inbyggda funktioner för webbutveckling. Det har använts i stor utsträckning inom webbutveckling i över 20 år. Även om det för närvarande driver nästan 80% av webbplatserna, har PHP några betydande svagheter. Att vara enkel-trådad är en av dem.
PHP har inte en standardfunktion för att skapa ytterligare trådar för bakgrundsprocesser. På grund av språkets enkeltrådade design kommer du att ha svårt att bygga även en enkel webbapplikation som måste skicka e-post. Att skicka ett e-postmeddelande är en dyr och tidskrävande process som kan blockera PHP:s enda tråd.
PHP-ramverk tar itu med problemet
PHP har ett stort antal ramverk med öppen källkod. Deras huvudmål är att minska utvecklingstiden för komplexa webbapplikationer genom att tillämpa fördefinierade koncept. De hjälper PHP-utvecklare att automatisera uppgifter, arbeta effektivt med olika typer av databaser, skydda applikationer mot välkända sårbarheter och utföra tester. De mest populära ramverken är Laravel, Zend, Symfony och Phalcon. Vart och ett av dem har sina egna fördelar och en enorm gemenskap som bidrar till kodbasen med öppen källkod.
Varje ramverk erbjuder en väg runt problemet med multi-threading i PHP. Om du vill ha en process som körs i bakgrunden är det allmänna konceptet följande: informationen om en uppgift skickas till en ködrivare/meddelandebuss medan servern ständigt kontrollerar listan över uppgifter för att se om det finns något att köra.
Hantera meddelandeköer i Laravel
Laravel har ett enhetligt kö-API som låter dig välja mellan olika tekniker som Redis, Amazon SQS, Beanstalkd eller till och med ett gammaldags relationsdatabassystem. Låt oss titta på hur Laravel fungerar med Redis, en öppen källkod för lagring av datastrukturer i minnet.
Vad är användningen av Redis i Laravel? Konceptuellt sett skickar du en uppgift (eller "dispatching a job", som det kallas i Laravels ekosystem) till Redis-kön där den väntar tills den plockas upp och bearbetas. För att bearbeta köer måste du ha arbetare som kör non-stop. På produktionsservrar bör du ha en Supervisor, en processövervakare som vanligtvis används i Linux-miljöer.
Låt oss säga att du har en User-modell som det ska skapas en instans av för varje ny registrering. Det finns inget standardiserat sätt att uppnå detta: allt handlar om preferenser. För att implementera det enkelt behöver du en observatör och ett köat jobb:
Observatören triggas när en instans av modellen skapas.
Observatören skickar jobbet till kön.
Supervisor fortsätter att köra queue:work
för projektet. Så snart ett nytt jobb skickas ut kommer det att behandlas av Laravels köarbetare.
Låt oss titta på ett kodexempel.
Först måste du skapa en observatör för User-modellen och ett jobb:
php artisan make:observer UserObserver --model=User
php artisan make:job SendRegistrationEmail
Därefter måste du introducera det du just har skapat i programmet. Du kan göra det genom att registrera en observatör i EventServiceProvider
enligt följande:
namespace App\Providers;
class EventServiceProvider extends ServiceProvider
{
public function boot()
{
User::observe(UserObserver::class);
}
}
Din applikation har nu en definition av vad som ska observeras och du bör konfigurera den för att utföra jobbet. UserObserver
måste reagera när en instans av modellen User
skapas. Du kan uppnå detta genom att uppdatera observatörens created
-metod för den relaterade modellen. Låt oss få den att skicka ett e-postmeddelande 10 sekunder efter att modellinstansen har skapats för att se hur det fungerar i praktiken.
namespace App\Observers;
class UserObserver
{
public function created(User $user)
{
SendRegistrationEmail::dispatch($user->email)->delay(now()->addSeconds(10));
} }
}
Varje gång en User
skapas kommer jobbet SendRegistrationEmail
att skickas ut av observatören.
namespace App\Jobs;
class SendRegistrationEmail implements ShouldQueue
{
public $email;
public function __construct($email)
{
$this->email = $email;
}
public function handle()
{
$email = $this->email;
Mail::send([], [], function ($message) use ($email)
{
$message
->to($email)
->subject('Hej, världen!')
->setBody('Välkommen till applikationen!');
});
}
}
Så här implementerar du flödet. Nu skickar applikationen ett e-postmeddelande till en ny användare vid registrering.
För att få det att fungera via köer måste du uppdatera konfigurationerna så att Redis-drivrutinen används. När du har installerat Redis på din maskin räcker det med att uppdatera i .env
en gång:
QUEUE_CONNECTION=redis
Glöm sedan inte att uppdatera dina konfigurationer: php artisan config:cache
. För att starta Laravels köarbetare måste du köra php artisan queue:work
.
Lösa problem med Laravels köarbetare
Produktionsmiljöer kräver att du har köarbetarna igång hela tiden. Själva kommandot queue:work
kan misslyckas av många anledningar, t.ex. att den maximala timeouten överskrids. Att kontrollera servern manuellt för att se till att köarbetaren är uppe är inte ett alternativ. Istället ska du använda Supervisor, en processövervakare för Linux-miljöer.
När du har installerat Supervisor på servern måste du ge den en konfigurationsfil för att interagera med Laravels köarbetare. Låt oss skapa en laravel-worker.conf
-fil som hanterar queue:work
-processen.
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/project/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=root
numprocs=4
redirect_stderr=true
stdout_logfile=/home/project/logs/worker.log
stopwaitsecs=3600
I den här konfigurationen ska du säga till Supervisor att starta om arbetarna automatiskt och ha 4 parallella processer igång. Låt oss starta processerna:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
Sammanfattningsvis är detta så enkelt som du läser det. Supervisorn håller igång arbetarna. När kön får ett jobb kommer arbetarna att välja och köra det. På så sätt säkerställer du att användaren inte behöver vänta tills PHP bearbetar uppgiften att skicka ett e-postmeddelande och fortsätter till nästa sida genom att flytta detta tidskrävande jobb till "parallella" trådar.