skip to Main Content

My laravel application is behind load balancer and 2 EC2 instances are running simultaneously. Before I was managing cronjob on only one server but this is not ideal way because if load increased or something unusual error happen and if 3rd EC2 instance initialized then cronjob will start on that server too and my cronjob is performing critical task like stripe charge or expire subscriptions, and if both server perform cronjob task then user will charge on stripe multiple time.

So to tackle this situation I have implimented distributed locking using Redis. I changed my default cache driver from file to redis in .env file. CACHE_DRIVER=redis and in Console/Kernel.php added onOneServer method like this.

$schedule->command('subscription:autorenew')->everyMinute()->withoutOverlapping()->onOneServer();

now even both server has crontab enabled it is performing task on only one server but my deployment pipeline has command php artisan cache:clear due to that lock is being released even task is in progress, and second server also start performing the same task at same time.

Is there any laravel built in way where I can set my default CACHE_DRIVER=file and still use redis for distributed lock so that php artisan cache:clear do not affect the redis cache lock?

2

Answers


  1. Problem: The php artisan cache:clear command clears all cache, including Redis locks used by onOneServer(), causing tasks to run on both servers.

    Solution:

    Separate Redis Connection for Locks: In config/database.php, set up a new Redis connection (e.g., redis_lock) just for the onOneServer locks. This isolates the locks from general cache clearing.

    Avoid cache:clear in Production: Use specific commands like config:clear or cache:forget for specific keys instead of clearing everything.

    This setup prevents cache:clear from affecting your locks, ensuring onOneServer() works across EC2 instances as intended.

    Login or Signup to reply.
  2. you can avoid your problem by using a custom cache clear command that clears only certain tags:

    class ClearCacheOnDeployment extends Command
    {
      protected $signature = 'cache:flush-on-deploy';
    
      public function handle()
      {
        Cache::tags(['expires_on_deploy'])->flush();
    ...
    // example usage
    class SomeApiHandler
    {
      public function call()
      {
        $cache = Cache::tags(['expires_on_deploy']);
       
        if ($cache->has('some-key')) {
          return $cache->get('some-key');
        }
    
        // do api call
        ...
    
        $cache->put('some-key', $apiPayload, $this->ttl());
    
        return $apiPayload;
    

    but be careful using multiple tags, since if flushing a tag, data with multiple tags is not flushed unless all its tags are flushed.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search