<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>fsck.sh - English</title>
  <subtitle>A tech blog about system administration, development, and all things UNIX.</subtitle>
  <link href="https://fsck.sh/en/feed.xml" rel="self"/>
  <link href="https://fsck.sh/en/"/>
  <updated>2026-02-27T00:00:00Z</updated>
  <id>https://fsck.sh/en/</id>
  <author>
    <name>Matthias Breddin</name>
  </author>
  <entry>
    <title>Symfony Messenger Worker Stuck? 3 Silent Production Bugs</title>
    <link href="https://fsck.sh/en/blog/symfony-messenger-silent-bugs/"/>
    <updated>2026-02-27T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/symfony-messenger-silent-bugs/</id>
    <content xml:lang="en" type="html">&lt;p&gt;Sixteen minutes. Three bugs. Zero errors.&lt;/p&gt; &lt;p&gt;&lt;em&gt;Or: How Symfony Messenger convinced us everything was fine while doing absolutely nothing&lt;/em&gt;&lt;/p&gt; &lt;p&gt;We deployed a Symfony Messenger worker to production, watched it start, saw the familiar &lt;code&gt;[OK] Consuming messages from transport &quot;bulk_operations&quot;&lt;/code&gt; in the logs, and moved on. Messages piled up. The worker sat idle. No exceptions, no warnings, no failed jobs. Just silence.&lt;/p&gt; &lt;p&gt;What followed was a 16-minute debugging session that uncovered three independent bugs, each one invisible in its own way. Here’s the timeline.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Three bugs, three silent failures. (1) &lt;code&gt;auto_setup=0&lt;/code&gt; in the DSN meant the &lt;code&gt;messenger_messages&lt;/code&gt; table was never created — the worker logs OK anyway. (2) &lt;code&gt;use_notify: true&lt;/code&gt; is PostgreSQL-only; MySQL ignores it and never falls back to polling. (3) PHP-FPM wrote &lt;code&gt;Europe/Berlin&lt;/code&gt; timestamps while PHP CLI read them as UTC, delaying every background job by exactly one hour.&lt;/p&gt; &lt;h2 id=&quot;the-setup&quot; tabindex=&quot;-1&quot;&gt;The Setup&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/symfony-messenger-silent-bugs/#the-setup&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The Setup&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;The environment: Symfony 6.2, PHP 8.1, MySQL 8.0 on a bare-metal Ubuntu server. All findings below are specific to this stack — behaviour may differ across Symfony versions or with the Redis/AMQP transports. The background worker runs as a systemd service (a standard Linux mechanism for managing long-running background processes):&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# /etc/systemd/system/messenger.service&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span&gt;ExecStart=/usr/bin/php /var/www/app/bin/console messenger:consume bulk_operations --time-limit=3600 --memory-limit=128M&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span&gt;User=www-data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The transport uses Doctrine:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;# config/packages/messenger.yaml&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;framework&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; messenger&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; transports&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; bulk_operations&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; dsn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;%env(MESSENGER_TRANSPORT_DSN)%&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; options&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; use_notify&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; true&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; check_delayed_interval&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt; 60000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;And the DSN in &lt;code&gt;.env&lt;/code&gt;:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;MESSENGER_TRANSPORT_DSN&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;doctrine://default?&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;auto_setup&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Three configuration decisions. Three bugs. Let’s walk through them in the order we found them.&lt;/p&gt; &lt;h2 id=&quot;why-does-messenger-fail-with-a-missing-&#39;messenger_messages&#39;-table&quot; tabindex=&quot;-1&quot;&gt;Why Does Messenger Fail With a Missing ‘messenger_messages’ Table?&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/symfony-messenger-silent-bugs/#why-does-messenger-fail-with-a-missing-&#39;messenger_messages&#39;-table&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Why Does Messenger Fail With a Missing ‘messenger_messages’ Table?&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;The &lt;code&gt;messenger_messages&lt;/code&gt; table didn’t exist.&lt;/p&gt; &lt;p&gt;The DSN had &lt;code&gt;auto_setup=0&lt;/code&gt;, which tells Symfony’s Doctrine transport not to create its queue table automatically. This is a reasonable production setting — you don’t want your app creating database tables on the fly. But it assumes you’ve created the table yourself. We hadn’t.&lt;/p&gt; &lt;p&gt;Here’s the thing: &lt;code&gt;messenger_messages&lt;/code&gt; isn’t a Doctrine entity. There’s no migration for it, no entity class, nothing in &lt;code&gt;src/Entity/&lt;/code&gt;. It’s an internal transport table that Symfony manages outside your ORM layer. If you don’t let the transport create it and you don’t create it manually, it simply doesn’t exist.&lt;/p&gt; &lt;p&gt;The worker’s response to a missing table? &lt;code&gt;[OK] Consuming messages from transport &quot;bulk_operations&quot;&lt;/code&gt;. No error. No warning.…&lt;/p&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/symfony-messenger-silent-bugs/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Hunting a 0.18% Bug: Redis Lock Expiration in Crunz</title>
    <link href="https://fsck.sh/en/blog/redis-lock-expiration-crunz-bug/"/>
    <updated>2026-02-10T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/redis-lock-expiration-crunz-bug/</id>
    <content xml:lang="en" type="html">&lt;p&gt;&lt;em&gt;When “sporadic” means “mathematically inevitable”&lt;/em&gt;&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;In RedisStore.php line 185:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span&gt;[Symfony&#92;Component&#92;Lock&#92;Exception&#92;LockConflictedException]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;One line. No stack trace. No context. Just a &lt;code&gt;LockConflictedException&lt;/code&gt; showing up in our &lt;a href=&quot;https://github.com/crunzphp/crunz&quot;&gt;crunz&lt;/a&gt; scheduler logs — every single day. Sometimes once, sometimes a dozen times. No clear pattern, no obvious trigger. A textbook non-deterministic bug.&lt;/p&gt; &lt;p&gt;I ignored it for a while. Then I did the math.&lt;/p&gt; &lt;p&gt;Turns out this wasn’t random at all. It was a probabilistic certainty baked into crunz’s lock refresh mechanism — a bug that hits roughly 1 in every 550 lock operations. With 42 Redis-locked cron jobs running on schedules throughout the day, the question was never &lt;em&gt;if&lt;/em&gt; it happens, but &lt;em&gt;how often&lt;/em&gt;.&lt;/p&gt; &lt;h2 id=&quot;what&#39;s-a-lock-and-why-does-it-expire&quot; tabindex=&quot;-1&quot;&gt;What’s a Lock, and Why Does It Expire?&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/redis-lock-expiration-crunz-bug/#what&#39;s-a-lock-and-why-does-it-expire&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;What’s a Lock, and Why Does It Expire?&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;If you’re already comfortable with distributed locking and mutual exclusion, skip ahead. For everyone else — a quick mental model.&lt;/p&gt; &lt;p&gt;Think of a lock like a parking meter. You feed it coins (a TTL — time to live), and as long as there’s time on the meter, the parking spot is yours. Nobody else can take it. But the moment it runs out, the spot is fair game — even if you’re still in the store buying groceries.&lt;/p&gt; &lt;p&gt;Redis locks work the same way. Crunz — a PHP cron job scheduler — uses the Symfony Lock component with a &lt;code&gt;RedisStore&lt;/code&gt; to prevent overlapping task execution. When a task starts, it acquires a lock with a time limit via &lt;code&gt;ZADD&lt;/code&gt; (Redis’s “sorted set add” command — it stores a unique token with a score representing the expiration timestamp). As long as the task keeps refreshing that lock before it expires, it’s safe. But if the refresh comes too late — even by a fraction of a second — Redis considers the lock gone. The next refresh attempt finds an empty spot and throws &lt;code&gt;LockConflictedException&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;The twist: crunz doesn’t refresh the lock reliably. It uses a probabilistic approach. More on that in a moment.&lt;/p&gt; &lt;h2 id=&quot;redis-distributed-locks-in-php&quot; tabindex=&quot;-1&quot;&gt;Redis Distributed Locks in PHP&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/redis-lock-expiration-crunz-bug/#redis-distributed-locks-in-php&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Redis Distributed Locks in PHP&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;A distributed lock with Redis ensures that only one process runs a critical section at a time — even across multiple servers. In PHP, the Symfony Lock component makes this straightforward. Here’s a basic Redis lock example:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; Symfony&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;&#92;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;&#92;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;&#92;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;LockFactory&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; Symfony&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;&#92;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;&#92;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;&#92;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;Store&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;&#92;…&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/redis-lock-expiration-crunz-bug/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>PHP: The Cockroach of Programming Languages (And Why That&#39;s a Compliment)</title>
    <link href="https://fsck.sh/en/blog/php-the-cockroach-of-programming-languages/"/>
    <updated>2026-01-29T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/php-the-cockroach-of-programming-languages/</id>
    <content xml:lang="en" type="html">&lt;p&gt;&lt;em&gt;Unkillable, unfashionable, undeniably employed&lt;/em&gt;&lt;/p&gt; &lt;p&gt;In 2011, an article titled “PHP is Dying” made its rounds. The author predicted that within five years, PHP would be relegated to legacy maintenance. That was 15 years ago. PHP still powers 73.3% of websites with detectable server-side technology (W3Techs, January 2026).&lt;/p&gt; &lt;p&gt;I’ve been writing PHP since 2002. For 15 of those years, it’s been my primary income as a freelancer. I’ve worked with Symfony since version 2. And every few years, someone confidently tells me my career choice is dying.&lt;/p&gt; &lt;p&gt;They’re still wrong. But they’re not entirely without points.&lt;/p&gt; &lt;h2 id=&quot;the-critics-have-some-points&quot; tabindex=&quot;-1&quot;&gt;The Critics Have Some Points&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/php-the-cockroach-of-programming-languages/#the-critics-have-some-points&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The Critics Have Some Points&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Let’s be honest: PHP has real problems. Acknowledging them makes us better developers, not disloyal ones.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The stdlib is chaos.&lt;/strong&gt; Parameter order is inconsistent (&lt;code&gt;strpos($haystack, $needle)&lt;/code&gt; vs &lt;code&gt;array_search($needle, $haystack)&lt;/code&gt;). Naming conventions are all over the place (&lt;code&gt;str_replace&lt;/code&gt; vs &lt;code&gt;substr&lt;/code&gt; vs &lt;code&gt;string_starts_with&lt;/code&gt;). This isn’t defensible. It’s historical baggage from rapid, community-driven growth in the early years.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Unicode handling is bolted on.&lt;/strong&gt; You need &lt;code&gt;mb_*&lt;/code&gt; functions for proper multibyte support, and forgetting to use them causes subtle bugs. In 2026, this still isn’t first-class.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Legacy code gives PHP a bad name.&lt;/strong&gt; A lot of PHP in the wild is genuinely awful. Unmaintained WordPress plugins, spaghetti from 2008, raw SQL everywhere. When critics say “PHP code is bad,” they’re often looking at code that would be bad in any language, but PHP’s low barrier to entry means there’s more of it visible.&lt;/p&gt; &lt;p&gt;These are legitimate criticisms. If someone focuses on these points, they’re being fair.&lt;/p&gt; &lt;h2 id=&quot;why-the-myth-persists&quot; tabindex=&quot;-1&quot;&gt;Why the Myth Persists&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/php-the-cockroach-of-programming-languages/#why-the-myth-persists&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Why the Myth Persists&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;So if PHP has real problems, why do I call “PHP is dying” a myth? Because the predictions don’t track reality. The “PHP is dying” narrative has been continuous since at least 2004 (Slashdot discussions) through 2007 (early blog posts) to 2011 (mainstream tech press) to today.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Survivor bias works both ways.&lt;/strong&gt; Critics remember the terrible PHP 4 code they encountered. They don’t see the modern Symfony applications with strict typing, 100% test coverage, and clean architecture. Those applications just work quietly in production.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The hype cycle favors new things.&lt;/strong&gt; Node.js was “killing PHP” in 2012. Go was killing it in 2015. Rust in 2018. Each new language gets breathless coverage. PHP keeps shipping features and growing its ecosystem without the same fanfare.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Engagement farming.…&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/php-the-cockroach-of-programming-languages/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Meet Doppar: Laravel&#39;s Leaner, Faster Cousin</title>
    <link href="https://fsck.sh/en/blog/doppar-php-framework-speed-demon/"/>
    <updated>2026-01-28T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/doppar-php-framework-speed-demon/</id>
    <content xml:lang="en" type="html">&lt;p&gt;&lt;em&gt;Or: What happens when “fast enough” isn’t&lt;/em&gt;&lt;/p&gt; &lt;p&gt;318 requests per second. 1,000 concurrent users. Zero dropped connections.&lt;/p&gt; &lt;p&gt;Those are stress test results from &lt;a href=&quot;https://doppar.com/&quot;&gt;Doppar&lt;/a&gt;, a PHP framework you probably haven’t heard of. Laravel optimizes for developer experience. Symfony optimizes for enterprise stability. Doppar optimizes for raw speed — and lets you handle the rest.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Who this is for:&lt;/strong&gt; You’ve profiled your PHP application, optimized your queries, added caching, and still need more throughput. You’re comfortable writing integrations that would be a &lt;code&gt;composer require&lt;/code&gt; elsewhere. You want Laravel-like syntax without Laravel-like overhead.&lt;/p&gt; &lt;hr /&gt; &lt;h2 id=&quot;what-is-doppar&quot; tabindex=&quot;-1&quot;&gt;What Is Doppar?&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/doppar-php-framework-speed-demon/#what-is-doppar&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;What Is Doppar?&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Doppar is a high-performance, minimalist PHP framework that launched version 3.x in late 2025. It’s built on three principles:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Zero external dependencies&lt;/strong&gt; for core features&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Intelligent memoization&lt;/strong&gt; of repeated executions&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Attribute-first configuration&lt;/strong&gt;&lt;/li&gt; &lt;/ol&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; create-project&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; doppar/doppar&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; my-app&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; my-app&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; pool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; server:start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Your first route:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;// app/Http/Controllers/HelloController.php&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;#[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;Mapper&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;prefix&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;api&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2E8F82;--shiki-dark:#5DA994&quot;&gt; HelloController&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; Controller&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;{&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; #[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;Route&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;uri&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;hello/{name}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; methods&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; greet&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; Response&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; {&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; response&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;Hello, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;{$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;]);&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; }&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Requirements: PHP 8.3+ and Composer.&lt;/p&gt; &lt;hr /&gt; &lt;h2 id=&quot;history-and-philosophy&quot; tabindex=&quot;-1&quot;&gt;History &amp;amp; Philosophy&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/doppar-php-framework-speed-demon/#history-and-philosophy&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;History &amp;amp; Philosophy&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Doppar was created by &lt;a href=&quot;https://github.com/techmahedy&quot;&gt;techmahedy&lt;/a&gt;, a developer who wanted Laravel’s elegant syntax without the overhead. The &lt;a href=&quot;https://github.com/doppar/framework/releases&quot;&gt;3.x release in late 2025&lt;/a&gt; marked its transition from experiment to usable framework. It draws a parallel to Laravel’s own origin story — Symfony existed and was robust, yet Laravel found its voice by offering something different.&lt;/p&gt; &lt;p&gt;The philosophy is simple:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;“Need a feature? Install and use it. Don’t need it? Keep your application as simple and clean as possible.”&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;Doppar isn’t trying to replace Laravel or Symfony. It’s an alternative for developers who’ve squeezed every optimization out of their current stack and still need more.&lt;/p&gt; &lt;hr /&gt; &lt;h2 id=&quot;why-is-it-fast&quot; tabindex=&quot;-1&quot;&gt;Why Is It Fast?&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/doppar-php-framework-speed-demon/#why-is-it-fast&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Why Is It Fast?&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Three techniques make Doppar faster than typical PHP frameworks:&lt;/p&gt; &lt;h3 id=&quot;1.-intelligent-memoization&quot; tabindex=&quot;-1&quot;&gt;1. Intelligent Memoization&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/doppar-php-framework-speed-demon/#1.-intelligent-memoization&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;1. Intelligent Memoization&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Repeated executions are cached automatically. Configuration parsing, service resolution, route matching — anything that runs more than once gets memoized without manual intervention.&lt;/p&gt; &lt;h3 id=&quot;2.-zero-dependency-core&quot; tabindex=&quot;-1&quot;&gt;2. Zero-Dependency Core&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/doppar-php-framework-speed-demon/#2.-zero-dependency-core&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;2. Zero-Dependency Core&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;The ORM, validation, WebSocket server, and scheduler are built into the core.…&lt;/p&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/doppar-php-framework-speed-demon/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Spooky Action at a Distance: When Fixing Your Proxy Breaks Your Application</title>
    <link href="https://fsck.sh/en/blog/spooky-action-at-a-distance-proxy-fix-breaks-app/"/>
    <updated>2026-01-21T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/spooky-action-at-a-distance-proxy-fix-breaks-app/</id>
    <content xml:lang="en" type="html">&lt;p&gt;&lt;em&gt;Or: How I Learned That “Working” and “Correct” Are Not the Same Thing&lt;/em&gt;&lt;/p&gt; &lt;p&gt;“Spooky action at a distance” (&lt;em&gt;spukhafte Fernwirkung&lt;/em&gt;) is what Einstein called quantum entanglement in 1947—the phenomenon where measuring one particle instantly affects another, no matter how far apart they are. He meant it dismissively; the idea seemed absurd.&lt;/p&gt; &lt;p&gt;I first heard the term applied to software almost ten years ago, in Marco Pivetta’s (@ocramius) talk &lt;a href=&quot;https://ocramius.github.io/extremely-defensive-php/&quot;&gt;Extremely Defensive PHP&lt;/a&gt;. The concept stuck with me: code in one place mysteriously affecting code somewhere else, with no visible connection.&lt;/p&gt; &lt;p&gt;This is a story about that kind of bug.&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;“The ranking calculations aren’t running.”&lt;/p&gt; &lt;h2 id=&quot;the-system:-a-callback-based-pipeline&quot; tabindex=&quot;-1&quot;&gt;The System: A Callback-Based Pipeline&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/spooky-action-at-a-distance-proxy-fix-breaks-app/#the-system:-a-callback-based-pipeline&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The System: A Callback-Based Pipeline&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Our ranking tool queries a third-party API for search engine data. The pipeline looks simple enough:&lt;/p&gt; &lt;div class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;Diagram&quot;&gt;flowchart LR A[Send Task&lt;br /&gt;Command] --&amp;gt; B[External&lt;br /&gt;API] B --&amp;gt; C[Process&lt;br /&gt;Command] C --&amp;gt; D[Calculate&lt;br /&gt;Results]&lt;/div&gt;&lt;p&gt;Each task moves through a state machine tracked by three flags:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2E8F82;--shiki-dark:#5DA994&quot;&gt; AnalysisTask&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;{&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; private&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;submitted&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt; // Sent to external API?&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; private&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;completed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt; // API finished processing?&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; private&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;processed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt; // We fetched the results?&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The critical handoff happens via a &lt;strong&gt;webhook callback&lt;/strong&gt;: when the external API finishes processing, it sends an HTTP request to our callback endpoint, which sets &lt;code&gt;completed = true&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;Simple, right?&lt;/p&gt; &lt;h2 id=&quot;the-bug:-tasks-stuck-forever&quot; tabindex=&quot;-1&quot;&gt;The Bug: Tasks Stuck Forever&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/spooky-action-at-a-distance-proxy-fix-breaks-app/#the-bug:-tasks-stuck-forever&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The Bug: Tasks Stuck Forever&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Tasks were being created and submitted successfully. The external API was processing them (we verified via their dashboard). But our process command found nothing to do. They stopped processing mid November 2025.&lt;/p&gt; &lt;p&gt;I pulled up the processing logic:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; execute&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;InputInterface&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; OutputInterface&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; int&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;{&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;tasksToProcess&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;repository&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;findBy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;([&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;submitted&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;completed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt; // &amp;lt;-- Hmm...&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;processed&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; ]);&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; foreach&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; ($&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;tasksToProcess&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;task&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; {&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;processTask&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;($&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;task&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;);&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; }&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; Command&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;SUCCESS&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Wait. We’re looking for tasks where &lt;code&gt;completed = false&lt;/code&gt;?&lt;/p&gt; &lt;p&gt;If the callback sets &lt;code&gt;completed = true&lt;/code&gt; when the API finishes… why would we query for tasks that &lt;em&gt;haven’t&lt;/em&gt; completed?&lt;/p&gt; &lt;h2 id=&quot;the-assumption-trap&quot; tabindex=&quot;-1&quot;&gt;The Assumption Trap&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/spooky-action-at-a-distance-proxy-fix-breaks-app/#the-assumption-trap&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The Assumption Trap&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;I checked the callback controller:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;#[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;Route&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(…&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/spooky-action-at-a-distance-proxy-fix-breaks-app/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Setting Up HP iLO Hardware Monitoring with OMD Labs</title>
    <link href="https://fsck.sh/en/blog/hp-ilo-monitoring-omd-labs-setup/"/>
    <updated>2026-01-13T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/hp-ilo-monitoring-omd-labs-setup/</id>
    <content xml:lang="en" type="html">&lt;p&gt;Seven problems. That’s how many obstacles I counted before hardware monitoring for three HP ProLiant servers was finally working. The documentation made it sound so simple: enable SNMP, run check_hpasm, done.&lt;/p&gt; &lt;p&gt;&lt;em&gt;Or: How I learned that “community project” sometimes means “bring your own band-aids”&lt;/em&gt;&lt;/p&gt; &lt;p&gt;If you’re facing a similar setup – HP ProLiant servers monitored via iLO, OMD Labs as your monitoring system – this walkthrough will save you considerable frustration.&lt;/p&gt; &lt;h2 id=&quot;the-setup&quot; tabindex=&quot;-1&quot;&gt;The Setup&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/hp-ilo-monitoring-omd-labs-setup/#the-setup&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The Setup&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Three HP ProLiant DL360p Gen8 servers running VMware ESXi 7.0.3. Each server has an iLO4 management controller with its own network interface:&lt;/p&gt; &lt;table&gt; &lt;thead&gt; &lt;tr&gt; &lt;th&gt;Server&lt;/th&gt; &lt;th&gt;ESXi IP&lt;/th&gt; &lt;th&gt;iLO IP&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;esxi-01&lt;/td&gt; &lt;td&gt;192.168.20.x&lt;/td&gt; &lt;td&gt;192.168.21.101&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;esxi-02&lt;/td&gt; &lt;td&gt;192.168.20.x&lt;/td&gt; &lt;td&gt;192.168.21.102&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;esxi-03&lt;/td&gt; &lt;td&gt;192.168.20.x&lt;/td&gt; &lt;td&gt;192.168.21.103&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Comprehensive hardware monitoring – fans, temperatures, power supplies, RAM, RAID – via the iLO interface.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Monitoring System:&lt;/strong&gt; OMD Labs 5.60 (ConSol Edition) with Naemon as the core and PNP4Nagios for graphing.&lt;/p&gt; &lt;p&gt;Sounds straightforward? It wasn’t.&lt;/p&gt; &lt;h2 id=&quot;problem-1:-&amp;quot;failed-to-create-new-file:-invalid-path&amp;quot;&quot; tabindex=&quot;-1&quot;&gt;Problem 1: “Failed to create new file: invalid path”&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/hp-ilo-monitoring-omd-labs-setup/#problem-1:-%22failed-to-create-new-file:-invalid-path%22&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Problem 1: “Failed to create new file: invalid path”&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;The very first attempt to create a host through the Thruk web interface greeted me with an error:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Failed to create new file: invalid path&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;strong&gt;What happened?&lt;/strong&gt; The directory for configuration files simply didn’t exist. OMD Labs is a community project – some basic functionality isn’t perfectly configured out of the box.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt;&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;su&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; monitoring&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt; # As OMD site user&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; ~/etc/naemon/conf.d/hosts&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; ~/etc/naemon/conf.d/services&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; ~/etc/naemon/conf.d/commands&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;strong&gt;Lesson learned:&lt;/strong&gt; For production setups, it’s better to create configurations directly via CLI. The web interface is nice for quick wins but not always reliable.&lt;/p&gt; &lt;h2 id=&quot;the-esxi-snmp-detour&quot; tabindex=&quot;-1&quot;&gt;The ESXi SNMP Detour&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/hp-ilo-monitoring-omd-labs-setup/#the-esxi-snmp-detour&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The ESXi SNMP Detour&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Before tackling iLO, we first tried monitoring ESXi itself via SNMP.&lt;/p&gt; &lt;h3 id=&quot;enabling-snmp-on-esxi&quot; tabindex=&quot;-1&quot;&gt;Enabling SNMP on ESXi&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/hp-ilo-monitoring-omd-labs-setup/#enabling-snmp-on-esxi&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Enabling SNMP on ESXi&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Via SSH to the ESXi host:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;esxcli&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; system&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; snmp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; --communities&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; public&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;esxcli&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; system&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; snmp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; --enable&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; true&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;esxcli&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; network&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; firewall&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; ruleset&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; --ruleset-id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; snmp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; --enabled&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;h3 id=&quot;problem-2:-snmp-mibs-not-loaded&quot; tabindex=&quot;-1&quot;&gt;Problem 2: SNMP MIBs Not Loaded&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/hp-ilo-monitoring-omd-labs-setup/#problem-2:-snmp-mibs-not-loaded&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Problem 2: SNMP MIBs Not Loaded&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;First test:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;snmpwalk&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; -v2c&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; esxi-01.example.com&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; sysDescr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Result:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sysDescr: Unknown Object Identifier (Sub-id not found: (top) -&amp;gt; sysDescr)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The SNMP MIBs weren’t loaded on the OMD server. No big deal – numeric OIDs are more universal anyway:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;snmpwalk&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; -v2c&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; esxi-01.example.com&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; .1.3.6.1.2.1.1.1.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Result:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;iso.3.6.1.2.1.1.1.0 = STRING: &quot;VMware ESXi 7.0.3 build-24411414 VMware, Inc. x86_64&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;strong&gt;Lesson learned:&lt;/strong&gt; Always…&lt;/p&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/hp-ilo-monitoring-omd-labs-setup/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>PHPStan Level 9: The Path to Bug-Free PHP</title>
    <link href="https://fsck.sh/en/blog/phpstan-level-9-strict-typing/"/>
    <updated>2025-12-26T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/phpstan-level-9-strict-typing/</id>
    <content xml:lang="en" type="html">&lt;p&gt;Three days. That’s how long I spent debugging a payment reconciliation bug that PHPStan would have caught in three seconds.&lt;/p&gt; &lt;p&gt;&lt;em&gt;Or: How I Learned to Stop Worrying and Love the Type System&lt;/em&gt;&lt;/p&gt; &lt;p&gt;The bug was subtle. Our API wrapper returned &lt;code&gt;null&lt;/code&gt; during maintenance windows, but only for certain transaction types. Our tests used mocks that never returned &lt;code&gt;null&lt;/code&gt;. Code review focused on the calculation logic, not the null-safety. Production? Production crashed at 3 AM on a Sunday.&lt;/p&gt; &lt;p&gt;PHPStan Level 9 would have screamed at us: “Parameter #2 $bankData of function reconcileTransaction() expects BankData, BankData|null given.”&lt;/p&gt; &lt;p&gt;That 3 AM incident changed how I think about type safety. Today, I’m going to show you how we eliminated 90% of our type-related bugs without writing a single additional test. The secret? Your compiler is smarter than your tests.&lt;/p&gt; &lt;h2 id=&quot;why-static-analysis-changes-everything&quot; tabindex=&quot;-1&quot;&gt;Why Static Analysis Changes Everything&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/phpstan-level-9-strict-typing/#why-static-analysis-changes-everything&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Why Static Analysis Changes Everything&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Remember the last time you saw this in production?&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;Fatal&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; Uncaught&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; Call&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; member&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; function&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; /var/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;www&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;PaymentProcessor&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;142&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;This happens because PHP is dynamically typed. Variables can be anything at runtime. Your IDE might warn you, your tests might catch 80% of cases, but that 20% finds its way to production at the worst possible time.&lt;/p&gt; &lt;p&gt;Static analysis tools like PHPStan analyze your code &lt;strong&gt;without running it&lt;/strong&gt;. They build a complete type graph of your application and tell you exactly where things will break before you deploy.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Traditional Testing:&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Write code&lt;/li&gt; &lt;li&gt;Write tests&lt;/li&gt; &lt;li&gt;Run tests&lt;/li&gt; &lt;li&gt;Deploy&lt;/li&gt; &lt;li&gt;Fix production bugs you didn’t test for&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;&lt;strong&gt;Static Analysis:&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Write code&lt;/li&gt; &lt;li&gt;Run PHPStan&lt;/li&gt; &lt;li&gt;Fix type errors&lt;/li&gt; &lt;li&gt;Deploy with confidence&lt;/li&gt; &lt;li&gt;Sleep through the night&lt;/li&gt; &lt;/ul&gt; &lt;h2 id=&quot;the-phpstan-level-journey-(0-9)&quot; tabindex=&quot;-1&quot;&gt;The PHPStan Level Journey (0-9)&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/phpstan-level-9-strict-typing/#the-phpstan-level-journey-(0-9)&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The PHPStan Level Journey (0-9)&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;PHPStan offers 10 levels of strictness, from “barely checking anything” to “your code is mathematically proven to not have type errors.” Each level catches progressively more subtle bugs.&lt;/p&gt; &lt;h3 id=&quot;level-0:-basic-existence-checks&quot; tabindex=&quot;-1&quot;&gt;Level 0: Basic Existence Checks&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/phpstan-level-9-strict-typing/#level-0:-basic-existence-checks&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Level 0: Basic Existence Checks&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;The gentlest introduction. PHPStan verifies that classes, functions, and methods you call actually exist.&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;// Level 0 catches this&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; UserrModel&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;();&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt; // Typo in class name&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;();&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt; // Class doesn&#39;t exist, method doesn&#39;t exist&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;// Level 0 allows this (but shouldn&#39;t)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; process&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;($&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; {&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;value…&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/phpstan-level-9-strict-typing/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Async PHP in Production: Fibers, ReactPHP, and Swoole Demystified</title>
    <link href="https://fsck.sh/en/blog/async-php-fibers-reactphp-swoole/"/>
    <updated>2025-12-19T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/async-php-fibers-reactphp-swoole/</id>
    <content xml:lang="en" type="html">&lt;h1 id=&quot;async-php-in-production:-fibers-reactphp-and-swoole-demystified&quot; tabindex=&quot;-1&quot;&gt;Async PHP in Production: Fibers, ReactPHP, and Swoole Demystified&lt;/h1&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/async-php-fibers-reactphp-swoole/#async-php-in-production:-fibers-reactphp-and-swoole-demystified&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Async PHP in Production: Fibers, ReactPHP, and Swoole Demystified&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;&lt;strong&gt;PHP can handle 10,000 concurrent connections. Here’s how.&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;PHP’s least understood superpower&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Three days. That’s how long I spent optimizing an API aggregation service that called 15 external APIs sequentially. The response time? A painful 2.1 seconds on average. Then I discovered async PHP, and that same service now responds in 520 milliseconds. That’s a 304% improvement without touching the business logic.&lt;/p&gt; &lt;p&gt;If you still think PHP is that slow, blocking, synchronous language from the LAMP stack era, you’re in for a surprise. In 2025, &lt;a href=&quot;https://medium.com/@mohamadshahkhajeh/async-php-in-2025-beyond-workers-with-fibers-reactphp-and-amp-e7de384c3ea6&quot;&gt;async PHP is no longer the exception&lt;/a&gt;. With Fibers in core since PHP 8.1, plus mature ecosystems like ReactPHP, Swoole, and Amp, PHP can drive low-latency APIs, WebSockets, and streaming pipelines without turning your codebase into callback hell.&lt;/p&gt; &lt;p&gt;Let me show you how async PHP works in production, when to use each approach, and how to avoid the pitfalls that will bite you at 3 AM.&lt;/p&gt; &lt;h2 id=&quot;the-php-performance-revolution-nobody-talks-about&quot; tabindex=&quot;-1&quot;&gt;The PHP Performance Revolution Nobody Talks About&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/async-php-fibers-reactphp-swoole/#the-php-performance-revolution-nobody-talks-about&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The PHP Performance Revolution Nobody Talks About&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Remember when handling concurrent operations in PHP meant either spinning up multiple processes (memory nightmare) or using threads (complexity nightmare)? Those days are over.&lt;/p&gt; &lt;p&gt;Here’s what async PHP can do today:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;Process 200 RSS feeds&lt;/strong&gt; in 2.3 seconds instead of 111 seconds (&lt;a href=&quot;https://www.phparch.com/2025/08/php-fibers-the-game-changer-that-makes-async-programming-feel-like-magic/&quot;&gt;463% improvement&lt;/a&gt;)&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Scrape 500+ web pages&lt;/strong&gt; in the time it used to take to process 100&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Handle 10x more concurrent users&lt;/strong&gt; while maintaining consistent response times&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Run WebSocket servers&lt;/strong&gt; that keep thousands of connections alive simultaneously&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;The secret? Cooperative multitasking through Fibers and event loops. Let’s break down what that actually means.&lt;/p&gt; &lt;h2 id=&quot;understanding-php-fibers:-the-foundation&quot; tabindex=&quot;-1&quot;&gt;Understanding PHP Fibers: The Foundation&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/async-php-fibers-reactphp-swoole/#understanding-php-fibers:-the-foundation&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Understanding PHP Fibers: The Foundation&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;PHP 8.1 introduced &lt;a href=&quot;https://php.watch/versions/8.1/fibers&quot;&gt;Fibers&lt;/a&gt; as full-stack, interruptible functions. Think of them as lightweight threads that you can pause and resume at will, but without the complexity of true parallelism.&lt;/p&gt; &lt;p&gt;Here’s the crucial difference: Fibers are about &lt;strong&gt;concurrency&lt;/strong&gt;, not &lt;strong&gt;parallelism&lt;/strong&gt;. You’re not running multiple CPU-bound tasks simultaneously. You’re efficiently juggling multiple I/O-bound operations while one waits, another runs.&lt;/p&gt; &lt;h3 id=&quot;your-first-fiber:-the-&amp;quot;aha&amp;quot;-moment&quot; tabindex=&quot;-1&quot;&gt;Your First Fiber: The “Aha” Moment&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/async-php-fibers-reactphp-swoole/#your-first-fiber:-the-%22aha%22-moment&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Your First Fiber: The “Aha” Moment&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;php&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;fiber&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; Fiber&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; {&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;Fiber started&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt;&#92;n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt; // Suspend execution and return control&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; $…&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/async-php-fibers-reactphp-swoole/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Laravel vs Symfony 2025: When to Use Which</title>
    <link href="https://fsck.sh/en/blog/laravel-vs-symfony-2025-comparison/"/>
    <updated>2025-12-12T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/laravel-vs-symfony-2025-comparison/</id>
    <content xml:lang="en" type="html">&lt;h1 id=&quot;laravel-vs-symfony-2025:-when-to-use-which&quot; tabindex=&quot;-1&quot;&gt;Laravel vs Symfony 2025: When to Use Which&lt;/h1&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/laravel-vs-symfony-2025-comparison/#laravel-vs-symfony-2025:-when-to-use-which&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Laravel vs Symfony 2025: When to Use Which&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;&lt;em&gt;A pragmatic guide for choosing the right tool - because tribal wars don’t ship products&lt;/em&gt;&lt;/p&gt; &lt;p&gt;The framework war is over. Laravel won the popularity contest. Symfony won the enterprise battle. And here’s the plot twist: &lt;strong&gt;it doesn’t matter&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;What matters is choosing the right tool for your specific project. I’ve spent the last six months migrating a Laravel monolith to Symfony components, and another three months building a greenfield SaaS in Laravel. Both decisions were correct. Both would have been disasters if reversed.&lt;/p&gt; &lt;p&gt;Let me show you the decision framework I wish I’d had two years ago.&lt;/p&gt; &lt;h2 id=&quot;the-state-of-php-frameworks-in-2025&quot; tabindex=&quot;-1&quot;&gt;The State of PHP Frameworks in 2025&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/laravel-vs-symfony-2025-comparison/#the-state-of-php-frameworks-in-2025&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The State of PHP Frameworks in 2025&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Before we dive into philosophy and code, let’s look at the hard data from JetBrains’ State of PHP 2025 survey:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;Laravel&lt;/strong&gt;: 64% market share (1,720 PHP developers surveyed)&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Symfony&lt;/strong&gt;: 23% market share&lt;/li&gt; &lt;li&gt;&lt;strong&gt;WordPress&lt;/strong&gt;: 25% (yes, higher than Symfony, but it’s a CMS, not a framework)&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Others&lt;/strong&gt;: CodeIgniter, Yii, CakePHP combined under 10%&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Here’s what nobody tells you: &lt;strong&gt;Laravel runs on Symfony components&lt;/strong&gt;. Check your &lt;code&gt;vendor&lt;/code&gt; directory in any Laravel project - you’ll find &lt;code&gt;symfony/http-foundation&lt;/code&gt;, &lt;code&gt;symfony/routing&lt;/code&gt;, &lt;code&gt;symfony/console&lt;/code&gt;, and about a dozen more.&lt;/p&gt; &lt;p&gt;Laravel is Symfony with a gorgeous developer experience layer on top. Symfony is a collection of decoupled components that can power anything from a CLI tool to Laravel itself.&lt;/p&gt; &lt;h2 id=&quot;the-philosophy-gap&quot; tabindex=&quot;-1&quot;&gt;The Philosophy Gap&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/laravel-vs-symfony-2025-comparison/#the-philosophy-gap&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The Philosophy Gap&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;h3 id=&quot;laravel:-developer-happiness-first&quot; tabindex=&quot;-1&quot;&gt;Laravel: Developer Happiness First&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/laravel-vs-symfony-2025-comparison/#laravel:-developer-happiness-first&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Laravel: Developer Happiness First&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Laravel’s philosophy is radical simplicity combined with aesthetic pleasure. Taylor Otwell designed Laravel for developers who want to &lt;strong&gt;ship fast and enjoy the process&lt;/strong&gt;.&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;// Laravel Eloquent - this just feels nice to write&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;activeUsers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;active&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;posts&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;latest&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;paginate&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;15&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;);&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; view&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;users.index&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; compact&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;activeUsers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Everything about Laravel screams “get out of your way”. Convention over configuration. Batteries included. Opinionated defaults that work for 80% of use cases.&lt;/p&gt; &lt;h3 id=&quot;symfony:-flexibility-and-control&quot; tabindex=&quot;-1&quot;&gt;Symfony: Flexibility and Control&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/laravel-vs-symfony-2025-comparison/#symfony:-flexibility-and-control&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;Symfony: Flexibility and Control&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Symfony’s philosophy is professional-grade flexibility. Fabien Potencier built Symfony for teams who need &lt;strong&gt;precise control over…&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/laravel-vs-symfony-2025-comparison/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Symfony AssetMapper: Goodbye Webpack, Hello Simplicity</title>
    <link href="https://fsck.sh/en/blog/symfony-assetmapper-no-webpack/"/>
    <updated>2025-12-05T00:00:00Z</updated>
    <id>https://fsck.sh/en/blog/symfony-assetmapper-no-webpack/</id>
    <content xml:lang="en" type="html">&lt;p&gt;What if your frontend build process was just… nothing?&lt;/p&gt; &lt;p&gt;&lt;em&gt;The return to simplicity in frontend development&lt;/em&gt;&lt;/p&gt; &lt;p&gt;I’ve spent the last five years maintaining webpack configurations. Five years of &lt;code&gt;npm install&lt;/code&gt; taking three minutes. Five years of debugging why my build suddenly broke after updating a single package. Five years of explaining to junior developers why they need to learn an entirely separate ecosystem just to add a JavaScript file to a Symfony project.&lt;/p&gt; &lt;p&gt;Then Symfony 6.3 dropped AssetMapper, and I realized we’d been solving the wrong problem all along.&lt;/p&gt; &lt;p&gt;The promise is almost too good to be true: &lt;strong&gt;Write modern JavaScript and CSS with zero build system&lt;/strong&gt;. No Node.js, no npm, no webpack, no configuration files, no transpilation pipeline. Just PHP and the native features browsers have supported for years.&lt;/p&gt; &lt;p&gt;I was skeptical. You should be too. But after migrating three production applications, I’m convinced this is the future of Symfony frontend development.&lt;/p&gt; &lt;h2 id=&quot;the-problem-we-created-for-ourselves&quot; tabindex=&quot;-1&quot;&gt;The Problem We Created for Ourselves&lt;/h2&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/symfony-assetmapper-no-webpack/#the-problem-we-created-for-ourselves&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The Problem We Created for Ourselves&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Let me paint a familiar picture. You start a new Symfony project:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;symfony&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; my-project&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A65E2B;--shiki-dark:#C99076&quot;&gt; --webapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;In the “old days” (like… 2023), you’d immediately run:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; symfony/webpack-encore-bundle&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;And then you’d need to:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Install Node.js (specific version, of course)&lt;/li&gt; &lt;li&gt;Configure &lt;code&gt;webpack.config.js&lt;/code&gt;&lt;/li&gt; &lt;li&gt;Set up your &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt; &lt;li&gt;Deal with node_modules (hello, 400MB)&lt;/li&gt; &lt;li&gt;Configure Babel for transpilation&lt;/li&gt; &lt;li&gt;Set up watching in development&lt;/li&gt; &lt;li&gt;Configure build for production&lt;/li&gt; &lt;li&gt;Explain to your ops team why your Docker image is now 2GB&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;For what? To use &lt;code&gt;import&lt;/code&gt; statements in JavaScript. Features that browsers have supported natively since 2017.&lt;/p&gt; &lt;h3 id=&quot;the-webpack-rabbit-hole&quot; tabindex=&quot;-1&quot;&gt;The Webpack Rabbit Hole&lt;/h3&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://fsck.sh/en/blog/symfony-assetmapper-no-webpack/#the-webpack-rabbit-hole&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to &quot;The Webpack Rabbit Hole&quot;&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;p&gt;Here’s what a typical Encore setup looked like:&lt;/p&gt; &lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;// webpack.config.js&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt; Encore&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;@symfony/webpack-encore&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;);&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;Encore&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;setOutputPath&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;public/build/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;setPublicPath&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;/build&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;addEntry&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;./assets/app.js&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;splitEntryChunks&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;enableSingleRuntimeChunk&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;cleanupOutputBeforeBuild&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;enableBuildNotifications&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;enableSourceMaps&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;Encore&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;isProduction&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;())&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;enableVersioning&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;Encore&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;isProduction&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;())&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;configureBabel&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; {&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;plugins&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;@babel/plugin-proposal-class-properties&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;);&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; })&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;configureBabelPresetEnv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; {&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;useBuiltIns&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B56959;--shiki-dark:#C98A7D&quot;&gt;usage&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt;corejs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; })&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;enableSassLoader&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;enablePostCssLoader&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt;autoProvidejQuery&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;();&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;/span&gt; &lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#B07D48;--shiki-dark:#BD976A&quot;&gt; Encore&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.…&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;margin-top: 2em;&quot;&gt;&lt;a href=&quot;https://fsck.sh/en/blog/symfony-assetmapper-no-webpack/&quot;&gt;Continue reading on fsck.sh →&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
</feed>