feat: redis & laravel horizon
Laravel CI-CD (Gitea) / Tests Unitaires (push) Successful in 16s Details
Laravel CI-CD (Gitea) / Build & Push Docker (push) Failing after 6s Details
Laravel CI-CD (Gitea) / Déploiement Simplifié (push) Has been skipped Details

This commit is contained in:
Leon 2026-03-18 12:00:49 +01:00
parent e9bc15163c
commit a48b6ae4ab
7 changed files with 539 additions and 1 deletions

View File

@ -0,0 +1,36 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Horizon\Horizon;
use Laravel\Horizon\HorizonApplicationServiceProvider;
class HorizonServiceProvider extends HorizonApplicationServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
parent::boot();
// Horizon::routeSmsNotificationsTo('15556667777');
// Horizon::routeMailNotificationsTo('example@example.com');
// Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
}
/**
* Register the Horizon gate.
*
* This gate determines who can access Horizon in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewHorizon', function ($user = null) {
return in_array(optional($user)->email, [
//
]);
});
}
}

View File

@ -3,4 +3,5 @@
return [ return [
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
App\Providers\Filament\DashboardPanelProvider::class, App\Providers\Filament\DashboardPanelProvider::class,
App\Providers\HorizonServiceProvider::class,
]; ];

View File

@ -22,6 +22,7 @@ services:
- sail - sail
depends_on: depends_on:
- pgsql - pgsql
- redis
- meilisearch - meilisearch
pgsql: pgsql:
image: 'postgres:18-alpine' image: 'postgres:18-alpine'
@ -48,6 +49,21 @@ services:
- '${DB_USERNAME}' - '${DB_USERNAME}'
retries: 3 retries: 3
timeout: 5s timeout: 5s
redis:
image: 'redis:alpine'
ports:
- '${FORWARD_REDIS_PORT:-6378}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test:
- CMD
- redis-cli
- ping
retries: 3
timeout: 5s
meilisearch: meilisearch:
image: 'getmeili/meilisearch:latest' image: 'getmeili/meilisearch:latest'
ports: ports:
@ -67,11 +83,35 @@ services:
- 'http://127.0.0.1:7700/health' - 'http://127.0.0.1:7700/health'
retries: 3 retries: 3
timeout: 5s timeout: 5s
horizon:
build:
context: ./vendor/laravel/sail/runtimes/8.5
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-worker/app
extra_hosts:
- 'host.docker.internal:host-gateway'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
IGNITION_LOCAL_SITES_PATH: '${PWD}'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- redis
command: 'php artisan horizon'
networks: networks:
sail: sail:
driver: bridge driver: bridge
volumes: volumes:
sail-pgsql: sail-pgsql:
driver: local driver: local
sail-redis:
driver: local
sail-meilisearch: sail-meilisearch:
driver: local driver: local

View File

@ -12,10 +12,12 @@
"filament/widgets": "^5.3", "filament/widgets": "^5.3",
"http-interop/http-factory-guzzle": "^1.2", "http-interop/http-factory-guzzle": "^1.2",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",
"laravel/horizon": "^5.45",
"laravel/sanctum": "^4.0", "laravel/sanctum": "^4.0",
"laravel/scout": "^11.0", "laravel/scout": "^11.0",
"laravel/tinker": "^2.10.1", "laravel/tinker": "^2.10.1",
"meilisearch/meilisearch-php": "^1.16", "meilisearch/meilisearch-php": "^1.16",
"predis/predis": "^3.4",
"scalar/laravel": "^0.2.0" "scalar/laravel": "^0.2.0"
}, },
"require-dev": { "require-dev": {

204
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "1b77e11c702fcc38f202aa5a9dbfef5a", "content-hash": "2a710ddb9f9c83cf6e70df03723922cc",
"packages": [ "packages": [
{ {
"name": "anourvalar/eloquent-serialize", "name": "anourvalar/eloquent-serialize",
@ -2442,6 +2442,86 @@
}, },
"time": "2026-02-24T14:35:15+00:00" "time": "2026-02-24T14:35:15+00:00"
}, },
{
"name": "laravel/horizon",
"version": "v5.45.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/horizon.git",
"reference": "80c4de73c56227c625e5a3c6bfaddff760ab0962"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/horizon/zipball/80c4de73c56227c625e5a3c6bfaddff760ab0962",
"reference": "80c4de73c56227c625e5a3c6bfaddff760ab0962",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-pcntl": "*",
"ext-posix": "*",
"illuminate/contracts": "^9.21|^10.0|^11.0|^12.0|^13.0",
"illuminate/queue": "^9.21|^10.0|^11.0|^12.0|^13.0",
"illuminate/support": "^9.21|^10.0|^11.0|^12.0|^13.0",
"laravel/sentinel": "^1.0",
"nesbot/carbon": "^2.17|^3.0",
"php": "^8.0",
"ramsey/uuid": "^4.0",
"symfony/console": "^6.0|^7.0|^8.0",
"symfony/error-handler": "^6.0|^7.0|^8.0",
"symfony/polyfill-php83": "^1.28",
"symfony/process": "^6.0|^7.0|^8.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^7.56|^8.37|^9.16|^10.9|^11.0",
"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.45.3"
},
"time": "2026-03-11T14:28:04+00:00"
},
{ {
"name": "laravel/prompts", "name": "laravel/prompts",
"version": "v0.3.13", "version": "v0.3.13",
@ -2644,6 +2724,65 @@
}, },
"time": "2026-03-10T19:16:37+00:00" "time": "2026-03-10T19:16:37+00:00"
}, },
{
"name": "laravel/sentinel",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/sentinel.git",
"reference": "7a98db53e0d9d6f61387f3141c07477f97425603"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sentinel/zipball/7a98db53e0d9d6f61387f3141c07477f97425603",
"reference": "7a98db53e0d9d6f61387f3141c07477f97425603",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/container": "^8.37|^9.0|^10.0|^11.0|^12.0|^13.0",
"php": "^8.0"
},
"require-dev": {
"laravel/pint": "^1.27",
"orchestra/testbench": "^6.47.1|^7.56|^8.37|^9.16|^10.9|^11.0",
"phpstan/phpstan": "^2.1.33"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Sentinel\\SentinelServiceProvider"
]
},
"branch-alias": {
"dev-main": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Laravel\\Sentinel\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
},
{
"name": "Mior Muhammad Zaki",
"email": "mior@laravel.com"
}
],
"support": {
"source": "https://github.com/laravel/sentinel/tree/v1.0.1"
},
"time": "2026-02-12T13:32:54+00:00"
},
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
"version": "v2.0.10", "version": "v2.0.10",
@ -4855,6 +4994,69 @@
}, },
"time": "2021-08-15T12:53:48+00:00" "time": "2021-08-15T12:53:48+00:00"
}, },
{
"name": "predis/predis",
"version": "v3.4.2",
"source": {
"type": "git",
"url": "https://github.com/predis/predis.git",
"reference": "2033429520d8997a7815a2485f56abe6d2d0e075"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/predis/predis/zipball/2033429520d8997a7815a2485f56abe6d2d0e075",
"reference": "2033429520d8997a7815a2485f56abe6d2d0e075",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"psr/http-message": "^1.0|^2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.3",
"phpstan/phpstan": "^1.9",
"phpunit/phpcov": "^6.0 || ^8.0",
"phpunit/phpunit": "^8.0 || ~9.4.4"
},
"suggest": {
"ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
},
"type": "library",
"autoload": {
"psr-4": {
"Predis\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Till Krüss",
"homepage": "https://till.im",
"role": "Maintainer"
}
],
"description": "A flexible and feature-complete Redis/Valkey client for PHP.",
"homepage": "http://github.com/predis/predis",
"keywords": [
"nosql",
"predis",
"redis"
],
"support": {
"issues": "https://github.com/predis/predis/issues",
"source": "https://github.com/predis/predis/tree/v3.4.2"
},
"funding": [
{
"url": "https://github.com/sponsors/tillkruss",
"type": "github"
}
],
"time": "2026-03-09T20:33:04+00:00"
},
{ {
"name": "psr/clock", "name": "psr/clock",
"version": "1.0.0", "version": "1.0.0",

254
config/horizon.php Normal file
View File

@ -0,0 +1,254 @@
<?php
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 Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where Horizon will be accessible from. If this
| setting is null, Horizon will reside under the same domain as the
| application. Otherwise, this value will serve as the subdomain.
|
*/
'domain' => env('HORIZON_DOMAIN'),
/*
|--------------------------------------------------------------------------
| 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' => 'default',
/*
|--------------------------------------------------------------------------
| 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(env('APP_NAME', 'laravel'), '_').'_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:default' => 60,
],
/*
|--------------------------------------------------------------------------
| 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' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'auto',
'autoScalingStrategy' => 'time',
'maxProcesses' => 1,
'maxTime' => 0,
'maxJobs' => 0,
'memory' => 128,
'tries' => 1,
'timeout' => 60,
'nice' => 0,
],
],
'environments' => [
'production' => [
'supervisor-1' => [
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
],
],
'local' => [
'supervisor-1' => [
'maxProcesses' => 3,
],
],
],
/*
|--------------------------------------------------------------------------
| File Watcher Configuration
|--------------------------------------------------------------------------
|
| The following list of directories and files will be watched when using
| the `horizon:listen` command. Whenever any directories or files are
| changed, Horizon will automatically restart to apply all changes.
|
*/
'watch' => [
'app',
'bootstrap',
'config/**/*.php',
'database/**/*.php',
'public/**/*.php',
'resources/**/*.php',
'routes',
'composer.lock',
'composer.json',
'.env',
],
];

View File

@ -2,7 +2,10 @@
use Illuminate\Foundation\Inspiring; use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
Artisan::command('inspire', function () { Artisan::command('inspire', function () {
$this->comment(Inspiring::quote()); $this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote'); })->purpose('Display an inspiring quote');
Schedule::command('horizon:snapshot')->everyFiveMinutes();