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.
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.
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.
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.