Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

arcanaer's avatar

Laravel API requests are slow with Nuxt frontend and Redis queues despite low CPU and RAM usage

I'm experiencing slow requests in my Laravel app hosted on a VPS (4 cores, 8 GB RAM), with a Nuxt 3 frontend. My setup involves frequent API calls to endpoints like /user and /globals to retrieve data used throughout the page. I'm using queues to handle text summarization via OpenAI's API, and results are broadcasted to the frontend to avoid blocking the application.

Here are some key points:

  • The /user and /globals endpoints are sometimes taking up to 20 seconds to respond, as tracked by Laravel Pulse. These endpoints can be hit up to 60 times per hour.
  • Each text summary queue can take up to 50 seconds to process, with around 30,000 summaries processed daily.
  • My queues are managed using Redis with Laravel Horizon.
  • Despite the heavy workload, my CPU usage is always below 20% and my RAM usage is around 1.8 GB.
  • Queries avg in telescope for these endpoints are .35ms

I'm trying to understand why my API requests are so slow despite having enough resources. Could it be an issue with Horizon, Redis, or something else within Laravel?

Any advice would be greatly appreciated!

User Endpoint

public function user(Request $request)
    {
        return new UserResource($request->user());
    }

Global Endpoint

 public function index(Request $request)
    {

        $products = Product::where('active', true)->where('slug', '=', 'pro')->get();
        $settings = Setting::whereIn('key', [
            Setting::FREE_ESSAY_LIMIT,
            Setting::FREE_QUIZ_LIMIT,
            Setting::FREE_PARAPHRASE_LIMIT_BY_DAY,
            Setting::FREE_SUMMARY_LIMIT_BY_DAY,
            Setting::FREE_SUMMARY_YOUTUBE_LIMIT,
            Setting::FREE_YOUTUBE_LENGTH_SECONDS,
            Setting::FREE_SUMMARY_TEXT_IMAGE_LIMIT,
            Setting::FREE_TEXT_IMAGE_LIMIT,
            Setting::HELP_CENTER_ENABLED,
        ])->get();

        $limits = [];

        foreach ($settings as $setting) {
            $limits[$setting->key] = $setting->value;
        }

        return response()->json([
            'products' => ProductResource::collection($products),
            'limits' => $limits,
        ]);
    }

Current PHP FMP Settings:

pm = dynamic

pm.max_children = 40

pm.start_servers = 6


pm.min_spare_servers = 4


pm.max_spare_servers = 8

I've increased limits in PHP FPM, but always i have logs like this:

2-Sep-2024 16:00:07] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 2 idle, and 10 total children
[12-Sep-2024 16:00:08] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 16 children, there are 3 idle, and 12 total children
[12-Sep-2024 16:00:09] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 3 idle, and 13 total children
[12-Sep-2024 16:00:17] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 3 idle, and 17 total children
[12-Sep-2024 16:26:33] NOTICE: Reloading in progress ...
[12-Sep-2024 16:26:33] NOTICE: reloading: execvp("/usr/sbin/php-fpm8.3", {"/usr/sbin/php-fpm8.3", "--nodaemonize", "--fpm-config", "/etc/php/8.3/fpm/php-fpm.conf"})
[12-Sep-2024 16:26:33] NOTICE: using inherited socket fd=8, "/run/php/php8.3-fpm.sock"
[12-Sep-2024 16:26:33] NOTICE: fpm is running, pid 95890
[12-Sep-2024 16:26:33] NOTICE: ready to handle connections
[12-Sep-2024 16:26:33] NOTICE: systemd monitor interval set to 10000ms
[12-Sep-2024 20:00:12] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 2 idle, and 15 total children
[12-Sep-2024 20:00:13] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 16 children, there are 2 idle, and 17 total children
[12-Sep-2024 20:00:18] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 1 idle, and 23 total children
[13-Sep-2024 10:47:47] NOTICE: Reloading in progress ...
[13-Sep-2024 10:47:47] NOTICE: reloading: execvp("/usr/sbin/php-fpm8.3", {"/usr/sbin/php-fpm8.3", "--nodaemonize", "--fpm-config", "/etc/php/8.3/fpm/php-fpm.conf"})
[13-Sep-2024 10:47:47] NOTICE: using inherited socket fd=8, "/run/php/php8.3-fpm.sock"
[13-Sep-2024 10:47:47] NOTICE: fpm is running, pid 95890
[13-Sep-2024 10:47:47] NOTICE: ready to handle connections
[13-Sep-2024 10:47:47] NOTICE: systemd monitor interval set to 10000ms
0 likes
2 replies
Snapey's avatar

not sure how the method you showed have any relation to Queues and AI jobs?

What are you doing in the ProductResource?

experimentor's avatar

@arcanaer the stats you posted suggest that this is a production application. Are you running redis and the queues also in the same VPS?

The CPU utilisation and RAM usage numbers may be misleading. I know from AWS that these numbers are shown as average for 5 minutes by default. Only when we dig deeper and look at max values per minute, we see the real load on the server.

My suggestion for Production Workloads: Separate servers for laravel application (user routes, views and controllers) and Jobs. Let the long running jobs work on a separate server.

Minor improvement suggestion: globals endpoint looks like it can be improved with caching the products, settings and limits ... unless they are dynamic.

Please or to participate in this conversation.