Troubleshooting
Common issues you may hit running AppStoreCat, and how to fix them.
Docker Issues
Section titled “Docker Issues”Containers do not start
Section titled “Containers do not start”Check whether the ports are already in use:
lsof -i :7460 # Check the backend portlsof -i :7461 # Check the frontend portFix: change the ports in the root .env file, or stop the conflicting process.
MySQL health check fails
Section titled “MySQL health check fails”MySQL takes a few seconds to start. Check the logs:
docker compose logs appstorecat-mysqlIf the issue persists, make sure the volume is not corrupted:
make clean # Remove volumesmake setup # RecreateRedis connection error
Section titled “Redis connection error”The backend waits for Redis to be reachable. In development, check:
docker compose ps appstorecat-redisIn production Redis is not used — make sure QUEUE_CONNECTION=database and CACHE_STORE=file are set.
Backend Issues
Section titled “Backend Issues”Scraper connection errors
Section titled “Scraper connection errors”If the backend cannot reach the scrapers:
- Check that the scrapers are running:
make ps - Verify the URLs in the
.envfile:- Development:
APPSTORE_API_URL=http://host.docker.internal:7462 - Production:
APPSTORE_API_URL=http://appstorecat-scraper-ios:7462
- Development:
- Test scraper health:
curl http://localhost:7462/health
Queue jobs are not being processed
Section titled “Queue jobs are not being processed”Check whether the workers are running:
docker compose exec appstorecat-server php artisan queue:work --onceRestart the workers:
docker compose exec appstorecat-server php artisan queue:restartJobs land in the failed_jobs table
Section titled “Jobs land in the failed_jobs table”List failed jobs:
docker compose exec appstorecat-server php artisan queue:failedCommon causes:
- The scraper service is down → restart the scraper
- Rate limit exceeded → jobs retry automatically
- The app was removed from the store → the scraper returns HTTP 404; check the
apps.is_availableflag (reachable in at least one store) and the per-countryapp_metrics.is_availableflags - Persistent failed items are picked up by
ReconcileFailedItemsJoband appear in thereconcilingphase ofsync_statuses
Retry all failed jobs:
docker compose exec appstorecat-server php artisan queue:retry allMigration errors
Section titled “Migration errors”If migrations fail:
# Check current migration statusdocker compose exec appstorecat-server php artisan migrate:status
# Run pending migrationsdocker compose exec appstorecat-server php artisan migrateFrontend Issues
Section titled “Frontend Issues”Blank page / API errors
Section titled “Blank page / API errors”Check the server URL configuration. The web forwards API calls to the server:
# Check frontend logsmake logs-webMake sure BACKEND_URL is set correctly in the frontend container’s environment.
Hot reload does not work
Section titled “Hot reload does not work”The frontend volume mount must include ./web:/app. Check that the Vite dev server is running:
make logs-webScraper Issues
Section titled “Scraper Issues”App Store scraper returns empty results
Section titled “App Store scraper returns empty results”Some category/country combinations are not supported by the App Store. This is expected and is logged as a warning.
Google Play scraper timeout
Section titled “Google Play scraper timeout”Google Play data fetches can be slower than App Store. Increase the timeout:
GPLAY_TIMEOUT=60Performance
Section titled “Performance”Slow sync jobs
Section titled “Slow sync jobs”Check the rate limit settings in config/appstorecat.php. The defaults are conservative:
- iOS sync: 5 jobs per minute
- Android sync: 5 jobs per minute
These can be raised if your IP is not being rate limited.
Database growth
Section titled “Database growth”The app_metrics and trending_chart_entries tables grow fastest. Consider:
- Lowering the batch size (
SYNC_{IOS,ANDROID}_TRACKED_BATCH_SIZE) to slow ingestion of competitor / discovered apps - Disabling daily chart sync for the platform you don’t need (
CHART_{IOS,ANDROID}_DAILY_SYNC_ENABLED=false) - Narrowing the active country list via
countries.is_active_{ios,android}
Sync Pipeline
Section titled “Sync Pipeline”What happens when failed sync items pile up?
Section titled “What happens when failed sync items pile up?”The sync pipeline is split into phases (identity → listings → metrics → finalize → reconciling) and progress is tracked in the sync_statuses table. Failed items are automatically picked up and retried by ReconcileFailedItemsJob. For manual inspection:
make artisan tinker>>> \App\Models\SyncStatus::where('phase', 'reconciling')->latest()->take(20)->get();Queues are blocked
Section titled “Queues are blocked”iOS and Android queues are separated by platform (sync-tracked-{ios,android}, sync-on-demand-{ios,android}, charts-{ios,android}). A slow one will not block the other. To see which queue has a backlog:
make artisan queue:monitor sync-tracked-ios,sync-tracked-android,sync-on-demand-ios,sync-on-demand-android