Is Your PHP Application a Fragile Butterfly? Time to Test It in Battle
\n\nImagine: Friday evening. You've just launched a long-awaited release. Everything works perfectly. You pour some tea, open Telegram... And then the database goes down. Or Redis. Or an external API. Sound familiar? If not, you've probably just never encountered real chaos.
\n\nIn the world of PHP development, it's common to rely on "hope." We write code, cover it with unit tests, sometimes even integration tests. But what happens when things don't go according to plan? When the server drops packets, the database responds with a 10-second delay, or the file system fills up?
\n\nThat's where Chaos Engineering comes in — a discipline that originated from the world of Netflix and large distributed systems. But don't close the article just yet: it works for regular PHP applications too, even if you have a monolith on Laravel or Symfony.
\n\nWhat is Chaos Engineering and Why Does a PHP Developer Need It?
\n\nChaos Engineering is the practice of experimenting on a system to uncover weaknesses before they manifest in a real failure. You intentionally introduce faults (disable services, delay responses, kill processes) and observe how your application behaves.
\n\nMany think: "I have a simple PHP application, why do I need this?" But let's be honest:
\n\n- \n
- Does your code rely on external APIs? Yes. \n
- Do you have caching via Redis or Memcached? Yes. \n
- Do you use queues (RabbitMQ, Kafka, SQS)? Most likely, yes. \n
- Database — MySQL/PostgreSQL? Yes. \n
Each of these points is a potential point of failure. And the fault tolerance of a PHP application is only tested when something breaks. Chaos Engineering allows you to be the one who breaks things, not the one who fixes them.
\n\nBasic Principles of Chaos Engineering
\n\nBefore writing code, remember three main rules:
\n\n- \n
- Start small. Don't disable the entire database at once. Start with one connection. \n
- Have a hypothesis. "If Redis goes down, the application should still work, but slower" — that's a hypothesis. Test it. \n
- Automate rollback. Always have a plan to return to a normal state. \n
Now let's move on to real PHP examples.
\n\nExample 1: Emulating Database Delay
\n\nLet's say you have a typical query to MySQL. You use PDO. How do you check what happens if the database suddenly starts to "lag"?
\n\nThe simplest way is to write a middleware or wrapper for PDO that adds a random delay. Here's an example:
\n\n<?php\nclass ChaoticPDO extends PDO {\n private float $chaosProbability;\n private int $maxDelayMs;\n\n public function __construct(\n string $dsn, \n ?string $username = null, \n ?string $password = null, \n ?array $options = null,\n float $chaosProbability = 0.1, // 10% of requests will "lag"\n int $maxDelayMs = 5000 // maximum 5 seconds delay\n ) {\n parent::__construct($dsn, $username, $password, $options);\n $this->chaosProbability = $chaosProbability;\n $this->maxDelayMs = $maxDelayMs;\n }\n\n public function query(string $query, ?int $fetchMode = null, mixed ...$fetchModeArgs): PDOStatement|false\n {\n $this->maybeInjectDelay();\n return parent::query($query, $fetchMode, ...$fetchModeArgs);\n }\n\n private function maybeInjectDelay(): void {\n if (mt_rand() / mt_getrandmax() < $this->chaosProbability) {\n $delay = mt_rand(100, $this->maxDelayMs);\n usleep($delay * 1000);\n // Log for monitoring\n error_log("[CHAOS] Injected delay of {$delay}ms in database query");\n }\n }\n}\n\n// Usage\n$pdo = new Ch