Counting the current active users using Redis in Laravel without touching performance problem
Tags: laravel, php, webdev, redis
Published: 2023-03-09 15:10:53

If you want to know the number of users who are online, we can easily create a table called active_users and perform a user action to update the activity timestamp field. Once done, if you want active people, the activity timestamp is usually shown by calculating the number of users in the past 10 minutes or 5 minutes.

The easiest thing would be to just store the logged-in user activity in the database, but since every user's activity is recorded, it may slow down the application as more users register and login.

Instead, we are going to store every user action by logging it on the redis store instead of logging it in the database. Redis stores data mainly in memory, so it can be pretty fast for heavy input/output processes.

As an initial setup, Redis needs to be installed. After that, you must use the "Redis" driver in the cache store. So, in a Laravel app, just run:
        `composer require predis/predis`

This will install the php client redis package. You can read the detailed installation instructions at [This Link](https://l.facebook.com/l.php?u=https%3A%2F%2Flaravel.com%2Fdocs%2F5.4%2Fcache&h=ATOQPrVZu5ahnaCQ_Ybic1Pdx3PYlSrC9ppDLNcKMz9H7bUuyldQVF94QrG0qP19Ym39FlYRLCKjX5lUEkduZ8jK2H3byizPLk7sKIRf7ty0iyHP602HIqQ4WFM)

Let's surge ahead, like the Channellers of the Wheel of Time after setting up redis.

First, build the ActiveUserActivity middleware using the following command.

`php artisan make: middleware ActiveUserActivity`

Then, in the handle method of the ActiveUserActivity::class middleware, a different key, the user Id, is added together with the prefix 'online-users-' to record the activity of a user. ExpiredAt is set to 5 minutes, so if there is no user activiy within 5 minutes, redis will automatically cancel it. Example user with Id 17, "online-users-17" will be key of the cache.

```
if(auth()->check()) {
    $expiresAt = \Carbon\Carbon::now()->addMinutes(5);
    \Cache::put(
        ‘online-users-’ . auth()->user()->id, 
        auth()->user(), 
        $expiresAt
    );
}
```
After that, register the ActiveUserActivity::class middleware at the bottom of App\Http\Kernel.php as follows. Only then, every time the application process is done, the process will be done automatically.

If you don't want to run the application every time, declare it as routeMiddleware and register it in the route registration.

```
protected $middlewareGroups = [
  ‘web’ => [ 
    \App\Http\Middleware\EncryptCookies::class,
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \App\Http\Middleware\VerifyCsrfToken::class,
    \App\Http\Middleware\ActiveUserActivity::class,
  ],
  ‘api’ => [
     ‘throttle:60,1’,
  ],
];
```

The last step is to use the Redis keys command to determine the number of active users.

`count( Cache::keys(‘online-users-*’) );`

What I am personally doing is calling the count on my route code.

```
Route::get('online-users', function(){
        foreach(Redis::keys('laravel:online-users-*') as $key){    
            $cacheKeyWithoutPrefix=str_replace('laravel:','', $key);
            $user = Cache::get($cacheKeyWithoutPrefix);
            dd($user->id,$user->email,$user->name);
         }
    });
```

I hope this article has been helpful. Reach out if you encountered any issues or challenges.