Cette page a été traduite par la communauté et n'est pas forcément à jour. Consultez la version de référence (en anglais).
Cette page a été traduite par la communauté et n'est pas forcément à jour. Consultez la version de référence (en anglais).
Cette page a été traduite par la communauté et n'est pas forcément à jour. Consultez la version de référence (en anglais).
Les Workers d’extension permettent à votre extension FrankenPHP de gérer un pool dédié de threads PHP pour exécuter des tâches en arrière-plan, gérer des événements asynchrones ou implémenter des protocoles personnalisés. Cela se révèle utile pour les systèmes de files d’attente, les event listeners, les planificateurs, etc.
Si vous n’avez pas besoin de rendre le worker configurable par l’utilisateur (chemin de script fixe, nombre de threads fixe), vous pouvez simplement enregistrer le worker dans la fonction init().
package myextension
import (
"github.com/dunglas/frankenphp"
"github.com/dunglas/frankenphp/caddy"
)
// Handle global pour communiquer avec le pool de workers
var worker frankenphp.Workers
func init() {
// Enregistre le worker lorsque le module est chargé.
worker = caddy.RegisterWorkers(
"my-internal-worker", // Nom unique
"worker.php", // Chemin du script (relatif à l'exécution ou absolu)
2, // Nombre de threads fixe
// Hooks de cycle de vie optionnels
frankenphp.WithWorkerOnServerStartup(func() {
// Logique de configuration globale...
}),
)
}
Si vous prévoyez de partager votre extension (comme une file d’attente générique ou un écouteur d’événements), vous devriez l’envelopper dans un module Caddy. Cela permet aux utilisateurs de configurer le chemin du script et le nombre de threads via leur Caddyfile. Cela nécessite d’implémenter l’interface caddy.Provisioner et de parser le Caddyfile (voir un exemple).
Si vous intégrez FrankenPHP dans une application Go standard sans Caddy, vous pouvez enregistrer des workers d’extension en utilisant frankenphp.WithExtensionWorkers lors de l’initialisation des options.
Une fois le pool de workers actif, vous pouvez lui envoyer des tâches. Cela peut être fait à l’intérieur de fonctions natives exportées vers PHP, ou à partir de toute logique Go telle qu’un planificateur cron, un écouteur d’événements (MQTT, Kafka), ou toute autre goroutine.
SendMessageUtilisez SendMessage pour passer des données brutes directement à votre script worker. C’est idéal pour les files d’attente ou les commandes simples.
// #include <Zend/zend_types.h>
import "C"
import (
"context"
"unsafe"
"github.com/dunglas/frankenphp"
)
//export_php:function my_queue_push(mixed $data): bool
func my_queue_push(data *C.zval) bool {
// 1. S'assurer que le worker est prêt
if worker == nil {
return false
}
// 2. Envoyer au worker en arrière-plan
_, err := worker.SendMessage(
context.Background(), // Contexte Go standard
unsafe.Pointer(data), // Données à passer au worker
nil, // http.ResponseWriter optionnel
)
return err == nil
}
SendRequestUtilisez SendRequest si votre extension doit invoquer un script PHP qui s’attend à un environnement web standard (remplir $_SERVER, $_GET, etc.).
// #include <Zend/zend_types.h>
import "C"
import (
"net/http"
"net/http/httptest"
"unsafe"
"github.com/dunglas/frankenphp"
)
//export_php:function my_worker_http_request(string $path): string
func my_worker_http_request(path *C.zend_string) unsafe.Pointer {
// 1. Préparer la requête et l'enregistreur
url := frankenphp.GoString(unsafe.Pointer(path))
req, _ := http.NewRequest("GET", url, http.NoBody)
rr := httptest.NewRecorder()
// 2. Envoyer au worker
if err := worker.SendRequest(rr, req); err != nil {
return nil
}
// 3. Retourner la réponse capturée
return frankenphp.PHPString(rr.Body.String(), false)
}
Le script worker PHP s’exécute dans une boucle et peut gérer à la fois les messages bruts et les requêtes HTTP.
<?php
// Gérer à la fois les messages bruts et les requêtes HTTP dans la même boucle
$handler = function ($payload = null) {
// Cas 1 : Mode Message
if ($payload !== null) {
return "Received payload: " . $payload;
}
// Cas 2 : Mode HTTP (les superglobales PHP standards sont peuplées)
echo "Hello from page: " . $_SERVER['REQUEST_URI'];
};
while (frankenphp_handle_request($handler)) {
gc_collect_cycles();
}
FrankenPHP fournit des hooks pour exécuter du code Go à des points spécifiques du cycle de vie.
| Type de hook | Nom de l’option | Signature | Contexte et cas d’utilisation |
|---|---|---|---|
| Serveur | WithWorkerOnServerStartup | func() | Configuration globale. Exécuté Une fois. Exemple : Connexion à NATS/Redis. |
| Serveur | WithWorkerOnServerShutdown | func() | Nettoyage global. Exécuté Une fois. Exemple : Fermeture des connexions partagées. |
| Thread | WithWorkerOnReady | func(threadID int) | Configuration par thread. Appelé lorsqu’un thread démarre. Reçoit l’ID du Thread. |
| Thread | WithWorkerOnShutdown | func(threadID int) | Nettoyage par thread. Reçoit l’ID du Thread. |
package myextension
import (
"fmt"
"github.com/dunglas/frankenphp"
frankenphpCaddy "github.com/dunglas/frankenphp/caddy"
)
func init() {
workerHandle = frankenphpCaddy.RegisterWorkers(
"my-worker", "worker.php", 2,
// Démarrage du Serveur (Global)
frankenphp.WithWorkerOnServerStartup(func() {
fmt.Println("Extension : Démarrage du serveur...")
}),
// Thread Prêt (Par Thread)
// Note : La fonction accepte un entier représentant l'ID du Thread
frankenphp.WithWorkerOnReady(func(id int) {
fmt.Printf("Extension : Le thread worker #%d est prêt.\n", id)
}),
)
}