Slow Laravel IDE helper generation

2021-04-29

While working on a pretty standard headless Laravel app, I got really annoyed by how long composer install took whenever switching to branches with varying dependencies. Some hooks had been added recently, which invited the assumption that the experience would be the same for my peers. Retrospective was just around the corner, so I brought the topic up before taking a closer look myself, and was surprised that I was the only one suffering from this. Execution times were in the lower single-digit seconds for everyone else, while I was waiting nearly indefinitely.

Some details of the environment

The Laravel app and required services (database, cache...) are a set of containers, managed with docker-compose locally, and Kubernetes in production. The Composer lifecycle hooks (e.g. post-update-cmd) are used to for package discovery, generating IDE helpers, and generating some classes. Pretty standard stuff.

Although a database is part of the docker-compose setup, the one thing about our prod setup that is not pretty standard is the fact that the database needs to be shared with a legacy system that is hard to get rid of. In production, the database is a separate managed cloud thing and not part of the Kubernetes cluster. Locally, when working on anything related to the legacy system, this needs to be replicated for realistic testing with the legacy app.


Upon closer investigation, artisan ide-helper:meta was the one script executed by Composer that took a really long time to complete. This command generated meta data for PHPStorm, to provide better completion for methods with highgly dynamic parameters and return values. Verbose logging didn't shed more light on this, so the remaining option to narrow it down (save for debugging step by step into library code) was to divide and conquer by nuking the entire project setup, and starting from nothing to see which setup step makes it slow for me, and only me.

Things started failing when I restored the backup of my .env file. The contents are defaults for the most part, except for the database connection infos.

Cause

In my local setup, I run a standalone database to simulate the shared cloud database in production. Depending whether I'm working from home or at the company HQ, this has a different IP address. This was still a leftover from when I was less skilled at manipulating container networking, but it was still working reliably, so I kept it around. The only downside is that I had to swap database IP addresses whenever switching work sites.

For some reason that is not obvious when reading the sources of the artisan ide-helper:meta command, a working database connection is necessary. composer install was the first thing I did after switching environments, so it hadn't occurred to me yet that I could check whether the database connection infos fit my current situation.

With a similar cause, this could have also happened if using a containerized database that is only accessible from within a Docker network, yet trying to run the Artisan command on the host system.

Solution

I updated .env to use the database connection infos that fit my current environment and composer install was (comparatively) fast again.

Had this been caused by a database that's only accessible within the Docker network, I'd have executed composer install within the app container using docker-compose exec <app service name> composer install.