1

I have a Laravel app that uses two database connections.

One is always accessible (and is the default configured in my environment).

The other one is remote and may be unreachable (that's its expected behavior).

This second database is accessible only through a button. I want this button to be enabled only if the database is reachable.

For this, I am using a simple Livewire component that checks DB::('second_db')->getPdo();

Here is my component

// blade
<button wire:init="loadDisabled" class="..." {{ $this->disabled ? 'disabled' : '' }}>
    Access DB
</button>

// Component class
public $disabled = true;

function loadDisabled()
{
   try {
       DB::connection('second_db')->getPdo();
   } catch (PDOException $e) {
       $this->disabled = true;
   }
   $this->disabled = false;
}

public function render()
{
   return view('livewire.my-component');
}

When using Tinker, I tried DB::connection('second_db')->getPdo(); after a few seconds (a lot in my opinion), I got PDOException with message 'SQLSTATE[HY000] [335544721] Unable to complete network request to host "..." because the db was offline (that's what I expect) but when I tried it on the web with a page containing my livewire component, I got a 504 Gateway time-out from nginx

I even tried catching any exception with catch(Exception $e) but the same thing happened

I digged deeper and I realized it's due to the default valet-linux configuration.

When I searched for a solution, everyone was proposing to increase the timeout but I don't want that !

What I want to tell my program to do :

  1. Try for X seconds (say 5 seconds or even less) to get the pdo
  2. If that works, good, give me true
  3. If not, just throw PDOException (or whatever Exception is more appropriate for this case)
  4. Let me handle the exception in my catch block

Basically, I want my app to "decide to stop" before it triggers an nginx error because I know for a fact that if it takes that long, it's that my db is unreachable and that's what I'm looking for.

Fayçal Borsali
  • 402
  • 4
  • 17
  • Thank you for your comment. That's weird, I tried the proposed solution, it worked ... I removed the added code, it kept working ! – Fayçal Borsali Feb 04 '21 at 09:59

1 Answers1

0

You could go for parallel processing. Try using Laravel queues and pass results to a Notification instance, which will be reflected by your button element. Could take 3-5 seconds or so.

You could also go the Asynchronous way. The spatie/async package could help you run code in parallel, so you can connect to your database and simultaneously keep track of time. If the time elapses, you could always throw an exception.

With spatie/async your code looks more like this:

$pool
->add(function () {
    // Attempt your database connection
})
->then(function ($output) {
    // when successful, update livewire component
})
->catch(function ($exception) {
    // if you have a custom timeout exception, here's the best place
})
->timeout(function () {
    // or you let the package handle the timeout, perform your timeout action here 
});

learn more about that here: https://github.com/spatie/async#asynchronous-and-parallel-php

If you want more native control, it could lead you to some serious PHP code manipulation and I can suggest you start looking here: https://www.php.net/manual/en/function.set-time-limit.php#115057

Joshua Etim
  • 206
  • 2
  • 5
  • Thank you for your answer, I used the PHP native function, it worked, I removed it (for debugging purposes) it kept working ... weird – Fayçal Borsali Feb 04 '21 at 10:00