DEV Community

Cover image for Scale Real-Time APIs: Redis Pub/Sub in Laravel
Prajapati Paresh
Prajapati Paresh

Posted on • Originally published at smarttechdevs.in

Scale Real-Time APIs: Redis Pub/Sub in Laravel

The Database Polling Catastrophe

When engineering high-velocity metrics pipelines at Smart Tech Devs, real-time event streaming is standard practice. Imagine thousands of connected IoT devices or user sessions sending data updates every few seconds. A dangerous architectural flaw occurs when developers rely on relational databases (like PostgreSQL or MySQL) to poll for these incoming state changes continuously.

Forcing background workers to execute SELECT * FROM events WHERE status = 'pending' every 500 milliseconds creates an immense read-amplification storm. As table rows scale, your database disk I/O hits 100% capacity, transaction locks pile up, and your core data tier chokes. To handle high-throughput real-time updates cleanly, you must completely decouple raw messaging from your persistent storage layer using an ultra-fast **Redis Pub/Sub Worker Pool**.

The Mechanics of Redis Publish/Subscribe

Unlike standard disk-bound database queues, the Redis Publish/Subscribe (Pub/Sub) pattern operates entirely within system memory. It provides a lightweight, frictionless messaging channel where publishers push messages without caring who receives them, and subscribers listen to channels without querying tables.

When an active data socket pushes a payload, your API publishes the message to a designated Redis channel instantly. Dedicated, long-running Laravel queue workers stay actively connected to that memory channel. The moment a message drops, Redis pushes it directly into the worker's execution memory thread. The core relational database is never touched until the data has been fully compiled and is ready for safe batch persistence, dropping your query overhead to zero.

Step 1: Publishing Events Instantly via Redis

We push payloads onto the memory channel directly within the fast-path HTTP API Controller, returning a 202 response to the client in under 5 milliseconds.


namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;

class DeviceTelemetryController extends Controller
{
    public function ingest(Request $request)
    {
        $payload = $request->validate([
            'device_id' => 'required|string',
            'metrics' => 'required|array',
        ]);

        // Inject timestamp metadata securely
        $payload['processed_at'] = microtime(true);

        // ✅ THE ENTERPRISE PATTERN: Publish directly to memory.
        // Bypasses the disk queue completely for real-time throughput.
        Redis::publish('telemetry-stream', json_encode($payload));

        return response()->json(['status' => 'acknowledged'], 202);
    }
}

Step 2: Building the Dedicated Long-Running Listener

We build a dedicated custom Artisan command designed to run continuously as a system daemon, listening to the Redis channel thread without interruption.


namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
use App\Models\TelemetrySnapshot;

class ConsumeTelemetryStream extends Command
{
    protected $signature = 'stream:consume-telemetry';
    protected $description = 'Consume incoming events directly from the Redis Pub/Sub memory layer.';

    public function handle()
    {
        $this->info('Establishing connection to Redis Pub/Sub pipeline...');

        // Subscribe to the channel. This loop stays open natively in memory.
        Redis::subscribe(['telemetry-stream'], function (string $message) {
            $data = json_decode($message, true);

            // Execute heavy processing math here...
            $computedMetrics = $this->analyzePayload($data['metrics']);

            // Safely write the final calculated snapshot to persistent storage
            TelemetrySnapshot::create([
                'device_id' => $data['device_id'],
                'data' => $computedMetrics
            ]);
        });
    }

    private function analyzePayload(array $metrics): array
    {
        // Internal data-refining logic
        return array_filter($metrics, fn($val) => $val > 0);
    }
}

The Engineering ROI

By moving high-velocity notification streams out of relational tables and into a Redis Pub/Sub engine, you insulate your core database from connection exhaustion. Your API endpoints process spikes flawlessly because network ingestion is decoupled from disk operations. Your background pool processes events instantly in-memory, providing true real-time execution bounds that scale smoothly as your traffic expands.

Top comments (0)