Darkwood · Symfony 8 · Flow · Blackfire
app:flow:profile-demo · 3 démos Symfony
Le problème
while (true) {
$message = $queue->consume();
if (!$message) { sleep(1); continue; }
$this->process($message); // ← boîte noire
}
flowchart LR LOOP[Boucle worker] PROC[process opaque] BF[Blackfire] LOOP --> PROC PROC --> BF BF --> FLAT[Un gros bloc CPU]
Blackfire voit du PHP — pas une architecture.
La boucle n'est pas l'ennemi
while (true)
await() loop
$loop($next)
flowchart TB W[Worker Symfony] AW[flow await] D[Driver loop] J1[Job extract] J2[Job transform] J3[Job load] W --> AW --> D D --> J1 --> J2 --> J3
Pas la boucle infinie — c'est process() opaque.
Blackfire + signaux
bin/console app:flow:profile-demo -vv
kill -USR2 <pid> # start
kill -USR2 <pid> # stop → URL
flowchart LR RUN[Worker tourne] S1[SIGUSR2 start] WIN[Fenêtre profiling] S2[SIGUSR2 stop] URL[URL profil] RUN --> S1 --> WIN --> S2 --> URL
Profile les itérations — pas le boot du container.
Rôle de Flow
Flow rend la boucle profileable en transformant chaque itération en étapes d'exécution explicites.
$flow(new Ip($batch));
$flow->await(); // driver loop + jobs nommés
Démo 1
php-etl / Kiboko dans Flow
1 itération = 1 batch produit · github.com/matyo91/kibono-flow
Démo 2
Inspiré Flow PHP
Extractor → Transformer → Loader
Jobs d'orchestration
prepare → extract → transform → load
Hotspot CPU : NormalizeOrderTransformer (SHA-256 ×1000)
github.com/matyo91/php-flow · flow-php.com
Démo 3
Structure VibePHP · runtime factice reproductible
1 itération = 1 requête simulée · github.com/matyo91/vibephp-flow
Lecture du profil
Flow ne remplace pas Messenger. Il structure le code dans le worker.
Conclusion
Worker · driver · YFlow — trois boucles, une question : que se passe-t-il dans une itération ?