juanparati / laravel-timeout
Set a timeout to your Laravel queries.
12.0
2026-02-16 08:37 UTC
Requires
- php: >=8.2
- ext-pdo: *
- illuminate/support: >=12
Requires (Dev)
- laravel/pint: ^1.22
- orchestra/testbench: ^10.4
- phpunit/phpunit: ^11.5
README
Laravel Query Timeout ⏰
A Laravel database extension that implements query timeouts at the database level, helping you implement the circuit breaker pattern.
Compatible with the following RDBMS:
- MariaDB
- MySQL
- PostgreSQL
How it works.
Use the QueryTimeout facade to set a maximum execution time for your queries:
\QueryTimeout( 3 , // Interrupt if a query takes more than 3 seconds fn() => \DB::select('SELECT SLEEP(4)'), // Your query comes here (Use pg_sleep for testing with PostgreSQL) 'myconnection' // Database connection (Keep null for the default connection) );
In the previous example if the query exceeds the specified timeout (3 seconds), it will be terminated and throw a \Juanparati\QueryTimeout\QueryTimeoutException.
How it works under the hood
Instead of using co-routines or parallel execution monitoring, this library leverages native database features:
- MariaDB: max_statement_time
- MySQL: max_execution_time
- PostgreSQL: statement_timeout
The timeout mechanism works by:
- Setting the timeout value for the database session.
- Executing the query.
- Restoring the original timeout value even if the main query fails.
╔════════════════════════════════════════════════════════════════════════════════════════════════════╗
║ Example flow for MariaDB ║
║ ║
║ ┌─────────────────────────────────────────┐ ║
║ 1.│SET @@SESSION.max_statement_time=3; │ ◀─── Set the desired maximum time for the session ║
║ └─────────────────────────────────────────┘ ║
║ ┌─────────────────────────────────────────┐ ║
║ 2.│SELECT * FROM USERS; │ ◀─── Execute the query ║
║ └─────────────────────────────────────────┘ ║
║ ┌─────────────────────────────────────────┐ ║
║ 3.│SET @@SESSION.max_statement_time=0; │ ◀─── Restore the original session maximum time ║
║ └─────────────────────────────────────────┘ ║
╚════════════════════════════════════════════════════════════════════════════════════════════════════╝
Limitations
MySQL-specific
- Only "select" queries are timed out in MySQL.
- Unfortunately, for calculated queries MySQL kills the query silently without raising any error, so in this case query-timeout determines when a query is timed out measuring the execution time and creating artificially an exception.
MariaDB-specific
- Old MariaDB embedded servers may not work properly.
- COMMIT statements don't timeout in Galera clusters.
General Limitations:
- May be unreliable with persistent connections or connection pools in distributed environments
Best Practices
- Keep application logic outside the closure.
✅ Recommended:
$users = null; \QueryTimeout( 5, fn() => $users = User::where('name', 'like', 'john%')->get() ); foreach ($users as $user) { if ($user->password_expiration > now()) { ... // Your application logic } }
❌ Not recommended:
\QueryTimeout(
5,
function() {
$users = User::where('name', 'like', 'john%')->get()
foreach ($users as $user) {
if ($user->password_expiration > now()) {
... // Your application logic
}
}
}
);
- In MySQL, try to use only one query per closure (Be cautious with ORM operations that might trigger multiple queries).
Configuration
Publish configuration (Optional)
artisan vendor:publish --tag="query-timeout"