chore: add queue system (#7576)

This commit is contained in:
🏔️ Peak 2025-12-16 17:22:01 +01:00 committed by GitHub
commit c240955f4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 563 additions and 152 deletions

View file

@ -13,10 +13,11 @@ All notable changes to this project will be documented in this file.
- **v4 to v5 upgrade migration**
- Added Coolify v4 database as `old_pgsql` connection
-
- Worker Servers which replace build servers with servers that can also run jobs (horizon workers) in addition to building docker images
### Changed
- Upgraded all Composer and Node dependencies, most notably: PHP to 8.5 (previously 8.4), TailwindCSS to v4.0 (previously v3) and Laravel to v12 (previously v10)
- Upgraded all Composer and Node dependencies and adopted their latest syntax and features, most notably: PHP to 8.5 (previously 8.2), TailwindCSS to v4.0 (previously v3) and Laravel to v12 (previously v10)
- **Docker:**
- Upgraded all Docker dependencies, most notably: Postgres to v18 (previously v15) and Redis to v8 (previously v7)
-
@ -25,6 +26,11 @@ All notable changes to this project will be documented in this file.
- Use Redis for sessions and expire inactive sessions after 24h (previously 14 days)
- Encrypt user sessions data
- Expire password reset tokens after 10 minutes (previously 60 minutes)
- Jobs now wait for all DB transactions to be finished before being dispatched which prevents race conditions
- Normal jobs (backups, emails, etc.) and deployment jobs now use separate supervisor configurations and defaults
- Horizon workers are now restarted after 500 (job workers) or 300 (deployment workers) jobs or after 1 hour to clean up stale memory and CPU usage
- Reduced default queue timeouts from 10h to 60s for jobs and 300s for deployments to prevent stale jobs
- Increased `balanceCooldown` from 1s to 2s for jobs to reduce CPU spikes
- Redirect Laravel logs to `stderr` so they can be viewed in docker logs
- Configured production logging to rotate automatically and keep only the last 10 days of logs to reduce disk usage
- Changed production log level from `debug` to `warning` to reduce disk usage and avoid logging sensitive information
@ -44,6 +50,8 @@ All notable changes to this project will be documented in this file.
### Fixed
- `laravel.log` file growing indefinitely and consuming excessive disk space
- Removed logging of failed jobs into the database as we use Horizon for that and it can cause excessive disk usage in some cases
- On v4 when changing the maximum concurrent builds setting to more than 4 builds the setting is no longer respected because there is a maximum of 4 horizon workers available by default
-
### Security
@ -70,6 +78,7 @@ All notable changes to this project will be documented in this file.
- Automatically eager load all relationships to prevent N+1 queries
- Configure models and enforce morph map for polymorphic relationships
- Enforce immutable dates globally
- Disable queue interruption polling to improve performance
- Fake sleeps and prevent stray HTTP requests in testing
- Prevent exception truncation in development
- Use aggressive Vite prefetching for better performance
@ -83,13 +92,14 @@ All notable changes to this project will be documented in this file.
- Cancel in-progress action runs when a new run is triggered
- Improved `SECURITY.md` formatting and wording and added the support policy for `v5.x`
- Refactored the GitHub issue templates to use issue types and improved formatting and wording
- Moved `README.md` assets into `.github/assets/` to easier exclude them from the core repository code
- Moved `README.md` assets into `.github/assets/` to more easily exclude them from the core repository code
- Removed the `chore-remove-labels-and-assignees-on-close.yml` workflow as labels and assignees are now kept when closing Issues and PRs
### Refactored
- Completely refactored all database migrations for a cleaner, more consistent and stable database schema
- Completely refactored all database models
- Queues are now accessed via an enum instead of hardcoded strings
## Issues

View file

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace App\Enums;
enum ProcessingQueue: string
{
case Default = 'default';
case High = 'high';
case StandardDeployment = 'standard-deployment';
case ProductionDeployment = 'production-deployment';
case WorkerDefault = 'worker-default';
case WorkerHigh = 'worker-high';
case WorkerStandardDeployment = 'worker-standard-deployment';
case WorkerProductionDeployment = 'worker-production-deployment';
}

View file

@ -12,6 +12,7 @@ use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Vite;
use Illuminate\Support\ServiceProvider;
@ -35,6 +36,7 @@ final class AppServiceProvider extends ServiceProvider
$this->configureCommands();
$this->configureModels();
$this->configureDates();
$this->configureQueues();
$this->configureTests();
$this->configureRequestExceptions();
$this->configureVite();
@ -105,6 +107,14 @@ final class AppServiceProvider extends ServiceProvider
Date::use(CarbonImmutable::class);
}
/**
* Configure queues.
*/
private function configureQueues(): void
{
Queue::withoutInterruptionPolling();
}
/**
* Configure tests.
*/

View file

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Horizon\HorizonApplicationServiceProvider;
final class HorizonServiceProvider extends HorizonApplicationServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
parent::boot();
}
/**
* Register the Horizon gate.
*
* This gate determines who can access Horizon in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewHorizon', fn (): false => false);
}
}

View file

@ -4,4 +4,5 @@ declare(strict_types=1);
return [
App\Providers\AppServiceProvider::class,
App\Providers\HorizonServiceProvider::class,
];

View file

@ -9,6 +9,7 @@
"require": {
"php": "^8.5",
"laravel/framework": "^12.40.2",
"laravel/horizon": "^5.40",
"laravel/tinker": "^2.10.2"
},
"require-dev": {

268
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6045e019dfef5b1628b4762e35986357",
"content-hash": "273a008ce9e4578d53a4922fb59ff548",
"packages": [
{
"name": "brick/math",
@ -510,31 +510,31 @@
},
{
"name": "fruitcake/php-cors",
"version": "v1.3.0",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/fruitcake/php-cors.git",
"reference": "3d158f36e7875e2f040f37bc0573956240a5a38b"
"reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b",
"reference": "3d158f36e7875e2f040f37bc0573956240a5a38b",
"url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379",
"reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379",
"shasum": ""
},
"require": {
"php": "^7.4|^8.0",
"symfony/http-foundation": "^4.4|^5.4|^6|^7"
"php": "^8.1",
"symfony/http-foundation": "^5.4|^6.4|^7.3|^8"
},
"require-dev": {
"phpstan/phpstan": "^1.4",
"phpstan/phpstan": "^2",
"phpunit/phpunit": "^9",
"squizlabs/php_codesniffer": "^3.5"
"squizlabs/php_codesniffer": "^4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.3-dev"
}
},
"autoload": {
@ -565,7 +565,7 @@
],
"support": {
"issues": "https://github.com/fruitcake/php-cors/issues",
"source": "https://github.com/fruitcake/php-cors/tree/v1.3.0"
"source": "https://github.com/fruitcake/php-cors/tree/v1.4.0"
},
"funding": [
{
@ -577,7 +577,7 @@
"type": "github"
}
],
"time": "2023-10-12T05:21:21+00:00"
"time": "2025-12-03T09:33:47+00:00"
},
{
"name": "graham-campbell/result-type",
@ -1054,16 +1054,16 @@
},
{
"name": "laravel/framework",
"version": "v12.40.2",
"version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "1ccd99220b474500e672b373f32bd709ec38de50"
"reference": "509b33095564c5165366d81bbaa0afaac28abe75"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/1ccd99220b474500e672b373f32bd709ec38de50",
"reference": "1ccd99220b474500e672b373f32bd709ec38de50",
"url": "https://api.github.com/repos/laravel/framework/zipball/509b33095564c5165366d81bbaa0afaac28abe75",
"reference": "509b33095564c5165366d81bbaa0afaac28abe75",
"shasum": ""
},
"require": {
@ -1151,6 +1151,7 @@
"illuminate/process": "self.version",
"illuminate/queue": "self.version",
"illuminate/redis": "self.version",
"illuminate/reflection": "self.version",
"illuminate/routing": "self.version",
"illuminate/session": "self.version",
"illuminate/support": "self.version",
@ -1175,7 +1176,7 @@
"league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10",
"opis/json-schema": "^2.4.1",
"orchestra/testbench-core": "^10.8.0",
"orchestra/testbench-core": "^10.8.1",
"pda/pheanstalk": "^5.0.6|^7.0.0",
"php-http/discovery": "^1.15",
"phpstan/phpstan": "^2.0",
@ -1237,6 +1238,7 @@
"src/Illuminate/Filesystem/functions.php",
"src/Illuminate/Foundation/helpers.php",
"src/Illuminate/Log/functions.php",
"src/Illuminate/Reflection/helpers.php",
"src/Illuminate/Support/functions.php",
"src/Illuminate/Support/helpers.php"
],
@ -1245,7 +1247,8 @@
"Illuminate\\Support\\": [
"src/Illuminate/Macroable/",
"src/Illuminate/Collections/",
"src/Illuminate/Conditionable/"
"src/Illuminate/Conditionable/",
"src/Illuminate/Reflection/"
]
}
},
@ -1269,7 +1272,86 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-11-26T19:24:25+00:00"
"time": "2025-12-09T15:51:23+00:00"
},
{
"name": "laravel/horizon",
"version": "v5.40.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/horizon.git",
"reference": "005e5638478db9e25f7ae5cfb30c56846fbad793"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/horizon/zipball/005e5638478db9e25f7ae5cfb30c56846fbad793",
"reference": "005e5638478db9e25f7ae5cfb30c56846fbad793",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-pcntl": "*",
"ext-posix": "*",
"illuminate/contracts": "^9.21|^10.0|^11.0|^12.0",
"illuminate/queue": "^9.21|^10.0|^11.0|^12.0",
"illuminate/support": "^9.21|^10.0|^11.0|^12.0",
"nesbot/carbon": "^2.17|^3.0",
"php": "^8.0",
"ramsey/uuid": "^4.0",
"symfony/console": "^6.0|^7.0",
"symfony/error-handler": "^6.0|^7.0",
"symfony/polyfill-php83": "^1.28",
"symfony/process": "^6.0|^7.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^7.55|^8.36|^9.15|^10.8",
"phpstan/phpstan": "^1.10|^2.0",
"predis/predis": "^1.1|^2.0|^3.0"
},
"suggest": {
"ext-redis": "Required to use the Redis PHP driver.",
"predis/predis": "Required when not using the Redis PHP driver (^1.1|^2.0|^3.0)."
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Horizon": "Laravel\\Horizon\\Horizon"
},
"providers": [
"Laravel\\Horizon\\HorizonServiceProvider"
]
},
"branch-alias": {
"dev-master": "6.x-dev"
}
},
"autoload": {
"psr-4": {
"Laravel\\Horizon\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Dashboard and code-driven configuration for Laravel queues.",
"keywords": [
"laravel",
"queue"
],
"support": {
"issues": "https://github.com/laravel/horizon/issues",
"source": "https://github.com/laravel/horizon/tree/v5.40.2"
},
"time": "2025-11-28T20:12:12+00:00"
},
{
"name": "laravel/prompts",
@ -1836,20 +1918,20 @@
},
{
"name": "league/uri",
"version": "7.6.0",
"version": "7.7.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri.git",
"reference": "f625804987a0a9112d954f9209d91fec52182344"
"reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/uri/zipball/f625804987a0a9112d954f9209d91fec52182344",
"reference": "f625804987a0a9112d954f9209d91fec52182344",
"url": "https://api.github.com/repos/thephpleague/uri/zipball/8d587cddee53490f9b82bf203d3a9aa7ea4f9807",
"reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807",
"shasum": ""
},
"require": {
"league/uri-interfaces": "^7.6",
"league/uri-interfaces": "^7.7",
"php": "^8.1",
"psr/http-factory": "^1"
},
@ -1922,7 +2004,7 @@
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri-src/issues",
"source": "https://github.com/thephpleague/uri/tree/7.6.0"
"source": "https://github.com/thephpleague/uri/tree/7.7.0"
},
"funding": [
{
@ -1930,20 +2012,20 @@
"type": "github"
}
],
"time": "2025-11-18T12:17:23+00:00"
"time": "2025-12-07T16:02:06+00:00"
},
{
"name": "league/uri-interfaces",
"version": "7.6.0",
"version": "7.7.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri-interfaces.git",
"reference": "ccbfb51c0445298e7e0b7f4481b942f589665368"
"reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/ccbfb51c0445298e7e0b7f4481b942f589665368",
"reference": "ccbfb51c0445298e7e0b7f4481b942f589665368",
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/62ccc1a0435e1c54e10ee6022df28d6c04c2946c",
"reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c",
"shasum": ""
},
"require": {
@ -2006,7 +2088,7 @@
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri-src/issues",
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.6.0"
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.7.0"
},
"funding": [
{
@ -2014,7 +2096,7 @@
"type": "github"
}
],
"time": "2025-11-18T12:17:23+00:00"
"time": "2025-12-07T16:03:21+00:00"
},
{
"name": "monolog/monolog",
@ -2121,16 +2203,16 @@
},
{
"name": "nesbot/carbon",
"version": "3.10.3",
"version": "3.11.0",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon.git",
"reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f"
"reference": "bdb375400dcd162624531666db4799b36b64e4a1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
"reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/bdb375400dcd162624531666db4799b36b64e4a1",
"reference": "bdb375400dcd162624531666db4799b36b64e4a1",
"shasum": ""
},
"require": {
@ -2138,9 +2220,9 @@
"ext-json": "*",
"php": "^8.1",
"psr/clock": "^1.0",
"symfony/clock": "^6.3.12 || ^7.0",
"symfony/clock": "^6.3.12 || ^7.0 || ^8.0",
"symfony/polyfill-mbstring": "^1.0",
"symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0"
"symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0"
},
"provide": {
"psr/clock-implementation": "1.0"
@ -2222,7 +2304,7 @@
"type": "tidelift"
}
],
"time": "2025-09-06T13:39:36+00:00"
"time": "2025-12-02T21:04:28+00:00"
},
{
"name": "nette/schema",
@ -3289,22 +3371,21 @@
},
{
"name": "symfony/clock",
"version": "v7.4.0",
"version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/clock.git",
"reference": "9169f24776edde469914c1e7a1442a50f7a4e110"
"reference": "832119f9b8dbc6c8e6f65f30c5969eca1e88764f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110",
"reference": "9169f24776edde469914c1e7a1442a50f7a4e110",
"url": "https://api.github.com/repos/symfony/clock/zipball/832119f9b8dbc6c8e6f65f30c5969eca1e88764f",
"reference": "832119f9b8dbc6c8e6f65f30c5969eca1e88764f",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/clock": "^1.0",
"symfony/polyfill-php83": "^1.28"
"php": ">=8.4",
"psr/clock": "^1.0"
},
"provide": {
"psr/clock-implementation": "1.0"
@ -3343,7 +3424,7 @@
"time"
],
"support": {
"source": "https://github.com/symfony/clock/tree/v7.4.0"
"source": "https://github.com/symfony/clock/tree/v8.0.0"
},
"funding": [
{
@ -3363,20 +3444,20 @@
"type": "tidelift"
}
],
"time": "2025-11-12T15:39:26+00:00"
"time": "2025-11-12T15:46:48+00:00"
},
{
"name": "symfony/console",
"version": "v7.4.0",
"version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8"
"reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8",
"reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8",
"url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e",
"reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e",
"shasum": ""
},
"require": {
@ -3441,7 +3522,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.4.0"
"source": "https://github.com/symfony/console/tree/v7.4.1"
},
"funding": [
{
@ -3461,7 +3542,7 @@
"type": "tidelift"
}
],
"time": "2025-11-27T13:27:24+00:00"
"time": "2025-12-05T15:23:39+00:00"
},
{
"name": "symfony/css-selector",
@ -3912,16 +3993,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v7.4.0",
"version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "769c1720b68e964b13b58529c17d4a385c62167b"
"reference": "bd1af1e425811d6f077db240c3a588bdb405cd27"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/769c1720b68e964b13b58529c17d4a385c62167b",
"reference": "769c1720b68e964b13b58529c17d4a385c62167b",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/bd1af1e425811d6f077db240c3a588bdb405cd27",
"reference": "bd1af1e425811d6f077db240c3a588bdb405cd27",
"shasum": ""
},
"require": {
@ -3970,7 +4051,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.4.0"
"source": "https://github.com/symfony/http-foundation/tree/v7.4.1"
},
"funding": [
{
@ -3990,20 +4071,20 @@
"type": "tidelift"
}
],
"time": "2025-11-13T08:49:24+00:00"
"time": "2025-12-07T11:13:10+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v7.4.0",
"version": "v7.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "7348193cd384495a755554382e4526f27c456085"
"reference": "f6e6f0a5fa8763f75a504b930163785fb6dd055f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/7348193cd384495a755554382e4526f27c456085",
"reference": "7348193cd384495a755554382e4526f27c456085",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/f6e6f0a5fa8763f75a504b930163785fb6dd055f",
"reference": "f6e6f0a5fa8763f75a504b930163785fb6dd055f",
"shasum": ""
},
"require": {
@ -4089,7 +4170,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.4.0"
"source": "https://github.com/symfony/http-kernel/tree/v7.4.2"
},
"funding": [
{
@ -4109,7 +4190,7 @@
"type": "tidelift"
}
],
"time": "2025-11-27T13:38:24+00:00"
"time": "2025-12-08T07:43:37+00:00"
},
{
"name": "symfony/mailer",
@ -5352,16 +5433,16 @@
},
{
"name": "symfony/string",
"version": "v8.0.0",
"version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "f929eccf09531078c243df72398560e32fa4cf4f"
"reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/f929eccf09531078c243df72398560e32fa4cf4f",
"reference": "f929eccf09531078c243df72398560e32fa4cf4f",
"url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc",
"reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc",
"shasum": ""
},
"require": {
@ -5418,7 +5499,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v8.0.0"
"source": "https://github.com/symfony/string/tree/v8.0.1"
},
"funding": [
{
@ -5438,38 +5519,31 @@
"type": "tidelift"
}
],
"time": "2025-09-11T14:37:55+00:00"
"time": "2025-12-01T09:13:36+00:00"
},
{
"name": "symfony/translation",
"version": "v7.4.0",
"version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "2d01ca0da3f092f91eeedb46f24aa30d2fca8f68"
"reference": "770e3b8b0ba8360958abedcabacd4203467333ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/2d01ca0da3f092f91eeedb46f24aa30d2fca8f68",
"reference": "2d01ca0da3f092f91eeedb46f24aa30d2fca8f68",
"url": "https://api.github.com/repos/symfony/translation/zipball/770e3b8b0ba8360958abedcabacd4203467333ca",
"reference": "770e3b8b0ba8360958abedcabacd4203467333ca",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation-contracts": "^2.5.3|^3.3"
"php": ">=8.4",
"symfony/polyfill-mbstring": "^1.0",
"symfony/translation-contracts": "^3.6.1"
},
"conflict": {
"nikic/php-parser": "<5.0",
"symfony/config": "<6.4",
"symfony/console": "<6.4",
"symfony/dependency-injection": "<6.4",
"symfony/http-client-contracts": "<2.5",
"symfony/http-kernel": "<6.4",
"symfony/service-contracts": "<2.5",
"symfony/twig-bundle": "<6.4",
"symfony/yaml": "<6.4"
"symfony/service-contracts": "<2.5"
},
"provide": {
"symfony/translation-implementation": "2.3|3.0"
@ -5477,17 +5551,17 @@
"require-dev": {
"nikic/php-parser": "^5.0",
"psr/log": "^1|^2|^3",
"symfony/config": "^6.4|^7.0|^8.0",
"symfony/console": "^6.4|^7.0|^8.0",
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
"symfony/finder": "^6.4|^7.0|^8.0",
"symfony/config": "^7.4|^8.0",
"symfony/console": "^7.4|^8.0",
"symfony/dependency-injection": "^7.4|^8.0",
"symfony/finder": "^7.4|^8.0",
"symfony/http-client-contracts": "^2.5|^3.0",
"symfony/http-kernel": "^6.4|^7.0|^8.0",
"symfony/intl": "^6.4|^7.0|^8.0",
"symfony/http-kernel": "^7.4|^8.0",
"symfony/intl": "^7.4|^8.0",
"symfony/polyfill-intl-icu": "^1.21",
"symfony/routing": "^6.4|^7.0|^8.0",
"symfony/routing": "^7.4|^8.0",
"symfony/service-contracts": "^2.5|^3",
"symfony/yaml": "^6.4|^7.0|^8.0"
"symfony/yaml": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@ -5518,7 +5592,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/translation/tree/v7.4.0"
"source": "https://github.com/symfony/translation/tree/v8.0.1"
},
"funding": [
{
@ -5538,7 +5612,7 @@
"type": "tidelift"
}
],
"time": "2025-11-27T13:27:24+00:00"
"time": "2025-12-01T09:13:36+00:00"
},
{
"name": "symfony/translation-contracts",

285
config/horizon.php Normal file
View file

@ -0,0 +1,285 @@
<?php
declare(strict_types=1);
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Horizon Name
|--------------------------------------------------------------------------
|
| This name appears in notifications and in the Horizon UI. Unique names
| can be useful while running multiple instances of Horizon within an
| application, allowing you to identify the Horizon you're viewing.
|
*/
'name' => env('HORIZON_NAME'),
/*
|--------------------------------------------------------------------------
| Horizon Path
|--------------------------------------------------------------------------
|
| This is the URI path where Horizon will be accessible from. Feel free
| to change this path to anything you like. Note that the URI will not
| affect the paths of its internal API that aren't exposed to users.
|
*/
'path' => env('HORIZON_PATH', 'horizon'),
/*
|--------------------------------------------------------------------------
| Horizon Redis Connection
|--------------------------------------------------------------------------
|
| This is the name of the Redis connection where Horizon will store the
| meta information required for it to function. It includes the list
| of supervisors, failed jobs, job metrics, and other information.
|
*/
'use' => 'jobs',
/*
|--------------------------------------------------------------------------
| Horizon Redis Prefix
|--------------------------------------------------------------------------
|
| This prefix will be used when storing all Horizon data in Redis. You
| may modify the prefix when you are running multiple installations
| of Horizon on the same server so that they don't have problems.
|
*/
'prefix' => env(
'HORIZON_PREFIX',
Str::slug((string) env('APP_NAME', 'coolify'), '_').'_horizon:',
),
/*
|--------------------------------------------------------------------------
| Horizon Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will get attached onto each Horizon route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => ['web'],
/*
|--------------------------------------------------------------------------
| Queue Wait Time Thresholds
|--------------------------------------------------------------------------
|
| This option allows you to configure when the LongWaitDetected event
| will be fired. Every connection / queue combination may have its
| own, unique threshold (in seconds) before this event is fired.
|
*/
'waits' => [
'redis:high' => 10,
'redis:default' => 20,
'redis:production-deployment' => 10,
'redis:standard-deployment' => 20,
'redis:worker-high' => 10,
'redis:worker-default' => 20,
'redis:worker-production-deployment' => 10,
'redis:worker-standard-deployment' => 20,
],
/*
|--------------------------------------------------------------------------
| Job Trimming Times
|--------------------------------------------------------------------------
|
| Here you can configure for how long (in minutes) you desire Horizon to
| persist the recent and failed jobs. Typically, recent jobs are kept
| for one hour while all failed jobs are stored for an entire week.
|
*/
'trim' => [
'recent' => 60,
'pending' => 60,
'completed' => 60,
'recent_failed' => 10080,
'failed' => 10080,
'monitored' => 10080,
],
/*
|--------------------------------------------------------------------------
| Silenced Jobs
|--------------------------------------------------------------------------
|
| Silencing a job will instruct Horizon to not place the job in the list
| of completed jobs within the Horizon dashboard. This setting may be
| used to fully remove any noisy jobs from the completed jobs list.
|
*/
'silenced' => [
// App\Jobs\ExampleJob::class,
],
'silenced_tags' => [
// 'notifications',
],
/*
|--------------------------------------------------------------------------
| Metrics
|--------------------------------------------------------------------------
|
| Here you can configure how many snapshots should be kept to display in
| the metrics graph. This will get used in combination with Horizon's
| `horizon:snapshot` schedule to define how long to retain metrics.
|
*/
'metrics' => [
'trim_snapshots' => [
'job' => 24,
'queue' => 24,
],
],
/*
|--------------------------------------------------------------------------
| Fast Termination
|--------------------------------------------------------------------------
|
| When this option is enabled, Horizon's "terminate" command will not
| wait on all of the workers to terminate unless the --wait option
| is provided. Fast termination can shorten deployment delay by
| allowing a new instance of Horizon to start while the last
| instance will continue to terminate each of its workers.
|
*/
'fast_termination' => false,
/*
|--------------------------------------------------------------------------
| Memory Limit (MB)
|--------------------------------------------------------------------------
|
| This value describes the maximum amount of memory the Horizon master
| supervisor may consume before it is terminated and restarted. For
| configuring these limits on your workers, see the next section.
|
*/
'memory_limit' => 64,
/*
|--------------------------------------------------------------------------
| Queue Worker Configuration
|--------------------------------------------------------------------------
|
| Here you may define the queue worker settings used by your application
| in all environments. These supervisors and settings handle all your
| queued jobs and will be provisioned by Horizon during deployment.
|
*/
'defaults' => [
...((bool) env('IS_WORKER_SERVER', false) ? [] : [
'jobs' => [
'connection' => 'redis',
'queue' => ['high', 'default'],
'balance' => false,
'autoScalingStrategy' => 'time',
'maxTime' => 3600,
'maxJobs' => 500,
'memory' => 128,
'tries' => 1,
'timeout' => 60,
'sleep' => 3,
'workers-name' => 'jobs',
],
'deployments' => [
'connection' => 'redis',
'queue' => ['production-deployment', 'standard-deployment'],
'balance' => false,
'autoScalingStrategy' => 'time',
'maxTime' => 3600,
'maxJobs' => 300,
'memory' => 128,
'tries' => 1,
'timeout' => 300,
'sleep' => 3,
'workers-name' => 'deployments',
],
]),
...((bool) env('IS_WORKER_SERVER', false) ? [
'worker-jobs' => [
'connection' => 'redis',
'queue' => ['worker-high', 'worker-default'],
'balance' => false,
'autoScalingStrategy' => 'time',
'maxTime' => 3600,
'maxJobs' => 500,
'memory' => 128,
'tries' => 1,
'timeout' => 60,
'sleep' => 3,
'workers-name' => 'worker-jobs',
],
'worker-deployments' => [
'connection' => 'redis',
'queue' => ['worker-production-deployment', 'worker-standard-deployment'],
'balance' => false,
'autoScalingStrategy' => 'time',
'maxTime' => 3600,
'maxJobs' => 300,
'memory' => 128,
'tries' => 1,
'timeout' => 300,
'sleep' => 3,
'workers-name' => 'worker-deployments',
],
] : []),
],
'environments' => [
'*' => [
...((bool) env('IS_WORKER_SERVER', false) ? [] : [
'jobs' => [
'minProcesses' => env('HORIZON_JOBS_MIN_PROCESSES', 1),
'maxProcesses' => env('HORIZON_JOBS_MAX_PROCESSES', 4),
'balanceMaxShift' => env('HORIZON_JOBS_BALANCE_MAX_SHIFT', 1),
'balanceCooldown' => env('HORIZON_JOBS_BALANCE_COOLDOWN', 2),
],
'deployments' => [
'minProcesses' => env('HORIZON_DEPLOYMENTS_MIN_PROCESSES', 1),
'maxProcesses' => env('HORIZON_DEPLOYMENTS_MAX_PROCESSES', 2),
'balanceMaxShift' => env('HORIZON_DEPLOYMENTS_BALANCE_MAX_SHIFT', 1),
'balanceCooldown' => env('HORIZON_DEPLOYMENTS_BALANCE_COOLDOWN', 2),
],
]),
...((bool) env('IS_WORKER_SERVER', false) ? [
'worker-jobs' => [
'minProcesses' => env('HORIZON_JOBS_MIN_PROCESSES', 1),
'maxProcesses' => env('HORIZON_JOBS_MAX_PROCESSES', 6),
'balanceMaxShift' => env('HORIZON_JOBS_BALANCE_MAX_SHIFT', 2),
'balanceCooldown' => env('HORIZON_JOBS_BALANCE_COOLDOWN', 1),
],
'worker-deployments' => [
'minProcesses' => env('HORIZON_DEPLOYMENTS_MIN_PROCESSES', 1),
'maxProcesses' => env('HORIZON_DEPLOYMENTS_MAX_PROCESSES', 4),
'balanceMaxShift' => env('HORIZON_DEPLOYMENTS_BALANCE_MAX_SHIFT', 2),
'balanceCooldown' => env('HORIZON_DEPLOYMENTS_BALANCE_COOLDOWN', 1),
],
] : []),
],
],
];

View file

@ -14,7 +14,7 @@ return [
|
*/
'default' => env('QUEUE_CONNECTION', 'database'),
'default' => env('QUEUE_CONNECTION', 'redis'),
/*
|--------------------------------------------------------------------------
@ -35,58 +35,13 @@ return [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'connection' => env('DB_QUEUE_CONNECTION'),
'table' => env('DB_QUEUE_TABLE', 'jobs'),
'queue' => env('DB_QUEUE', 'default'),
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
'after_commit' => false,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
'queue' => env('BEANSTALKD_QUEUE', 'default'),
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
'block_for' => 0,
'after_commit' => false,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'default'),
'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'after_commit' => false,
],
'redis' => [
'driver' => 'redis',
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
'connection' => env('REDIS_QUEUE_CONNECTION', 'jobs'),
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
'block_for' => null,
'after_commit' => false,
],
'deferred' => [
'driver' => 'deferred',
],
'background' => [
'driver' => 'background',
],
'failover' => [
'driver' => 'failover',
'connections' => [
'database',
'deferred',
],
'after_commit' => true,
],
],
@ -102,7 +57,7 @@ return [
*/
'batching' => [
'database' => env('DB_CONNECTION', 'sqlite'),
'database' => env('DB_CONNECTION', 'pgsql'),
'table' => 'job_batches',
],
@ -120,8 +75,6 @@ return [
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
'database' => env('DB_CONNECTION', 'sqlite'),
'table' => 'failed_jobs',
'driver' => env('QUEUE_FAILED_DRIVER', 'null'),
],
];

View file

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('job_batches', function (Blueprint $table): void {
$table->string('id')->primary();
$table->string('name');
$table->integer('total_jobs');
$table->integer('pending_jobs');
$table->integer('failed_jobs');
$table->longText('failed_job_ids');
$table->mediumText('options')->nullable();
$table->integer('cancelled_at')->nullable();
$table->integer('created_at');
$table->integer('finished_at')->nullable();
});
}
};

View file

@ -3,6 +3,7 @@
declare(strict_types=1);
use Rector\Caching\ValueObject\Storage\FileCacheStorage;
use Rector\CodingStyle\Rector\ClassLike\NewlineBetweenClassLikeStmtsRector;
use Rector\Config\RectorConfig;
use Rector\Php80\Rector\NotIdentical\MbStrContainsRector;
use Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector;
@ -31,6 +32,7 @@ return RectorConfig::configure()
->withSkip([
__DIR__.'/bootstrap/cache',
AddOverrideAttributeToOverriddenMethodsRector::class,
NewlineBetweenClassLikeStmtsRector::class,
])
->withCache(__DIR__.'/storage/rector', FileCacheStorage::class)
->withPhpSets()

View file

@ -79,7 +79,6 @@ arch('Enums')
->toBeEnums()
->ignoring('App\Enums\Concerns')
->toExtendNothing()
->toImplementNothing()
->toHaveLineCountLessThan(80);
arch('Exceptions')