feat: enterprise-grade Docker setup for Dokploy deployment
- Add multi-stage Dockerfile (node-builder, composer-builder, production) - Add Nginx config with WebSocket proxy at /_ws path - Add PHP-FPM pool config, php.ini with OPcache tuning - Add Supervisord managing 7 processes: php-fpm, nginx, horizon, scheduler, reverb, pulse-check, pulse-work - Add entrypoint.sh with auto-migration, config caching, storage setup - Add .dockerignore and .env.production.example - Install laravel/horizon for production queue management and dashboard - Install laravel/pulse for production monitoring with Reverb integration - Configure TrustProxies middleware for HTTPS behind Traefik - Add horizon:snapshot to scheduler - Add VITE_REVERB_PATH for WebSocket path routing through Nginx
This commit is contained in:
24
.dockerignore
Normal file
24
.dockerignore
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
.git
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
.agents
|
||||||
|
.ai
|
||||||
|
.claude
|
||||||
|
.gemini
|
||||||
|
.junie
|
||||||
|
node_modules
|
||||||
|
vendor
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
*.md
|
||||||
|
!README.md
|
||||||
|
storage/logs/*
|
||||||
|
storage/framework/cache/*
|
||||||
|
storage/framework/sessions/*
|
||||||
|
storage/framework/views/*
|
||||||
|
tests/
|
||||||
|
phpunit.xml
|
||||||
|
phpunit.result.cache
|
||||||
|
docker-compose.yml
|
||||||
@@ -83,6 +83,7 @@ VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
|
|||||||
VITE_REVERB_HOST="${REVERB_HOST}"
|
VITE_REVERB_HOST="${REVERB_HOST}"
|
||||||
VITE_REVERB_PORT="${REVERB_PORT}"
|
VITE_REVERB_PORT="${REVERB_PORT}"
|
||||||
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
|
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
|
||||||
|
VITE_REVERB_PATH=""
|
||||||
|
|
||||||
ACTIVITY_LOGGER_ENABLED=true
|
ACTIVITY_LOGGER_ENABLED=true
|
||||||
ACTIVITY_LOGGER_TABLE_NAME=activity_log
|
ACTIVITY_LOGGER_TABLE_NAME=activity_log
|
||||||
|
|||||||
64
.env.production.example
Normal file
64
.env.production.example
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
APP_NAME=iMail
|
||||||
|
APP_ENV=production
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=false
|
||||||
|
APP_URL=https://your-domain.com
|
||||||
|
|
||||||
|
LOG_CHANNEL=stderr
|
||||||
|
LOG_LEVEL=info
|
||||||
|
|
||||||
|
# Database (MariaDB via Dokploy/External)
|
||||||
|
DB_CONNECTION=mariadb
|
||||||
|
DB_HOST=mariadb-host
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=imail
|
||||||
|
DB_USERNAME=root
|
||||||
|
DB_PASSWORD=
|
||||||
|
|
||||||
|
# MongoDB (via Dokploy/External)
|
||||||
|
MONGODB_URI=mongodb://mongodb-host:27017
|
||||||
|
|
||||||
|
# Redis (via Dokploy/External)
|
||||||
|
REDIS_CLIENT=phpredis # Required for Laravel Pulse ingest
|
||||||
|
REDIS_HOST=redis-host
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
CACHE_STORE=redis
|
||||||
|
QUEUE_CONNECTION=redis
|
||||||
|
SESSION_DRIVER=redis
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=reverb
|
||||||
|
|
||||||
|
FILESYSTEM_DISK=s3
|
||||||
|
|
||||||
|
# S3 Compatible Storage (RustFS via Dokploy/External)
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=imail
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=true
|
||||||
|
AWS_ENDPOINT=http://rustfs-host:9000
|
||||||
|
|
||||||
|
# Reverb Configuration
|
||||||
|
REVERB_APP_ID=
|
||||||
|
REVERB_APP_KEY=
|
||||||
|
REVERB_APP_SECRET=
|
||||||
|
REVERB_HOST="your-domain.com"
|
||||||
|
REVERB_PORT=443
|
||||||
|
REVERB_SCHEME=https
|
||||||
|
|
||||||
|
# Pulse Configuration
|
||||||
|
PULSE_INGEST_DRIVER=redis
|
||||||
|
PULSE_REDIS_CONNECTION=default
|
||||||
|
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
|
||||||
|
VITE_REVERB_HOST="${REVERB_HOST}"
|
||||||
|
VITE_REVERB_PORT="${REVERB_PORT}"
|
||||||
|
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
|
||||||
|
VITE_REVERB_PATH="/_ws"
|
||||||
@@ -46,8 +46,10 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
|||||||
- filament/filament (FILAMENT) - v4
|
- filament/filament (FILAMENT) - v4
|
||||||
- laravel/fortify (FORTIFY) - v1
|
- laravel/fortify (FORTIFY) - v1
|
||||||
- laravel/framework (LARAVEL) - v12
|
- laravel/framework (LARAVEL) - v12
|
||||||
|
- laravel/horizon (HORIZON) - v5
|
||||||
- laravel/pint (PINT) - v1
|
- laravel/pint (PINT) - v1
|
||||||
- laravel/prompts (PROMPTS) - v0
|
- laravel/prompts (PROMPTS) - v0
|
||||||
|
- laravel/pulse (PULSE) - v1
|
||||||
- laravel/reverb (REVERB) - v1
|
- laravel/reverb (REVERB) - v1
|
||||||
- livewire/flux (FLUXUI_FREE) - v2
|
- livewire/flux (FLUXUI_FREE) - v2
|
||||||
- livewire/livewire (LIVEWIRE) - v3
|
- livewire/livewire (LIVEWIRE) - v3
|
||||||
|
|||||||
@@ -46,8 +46,10 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
|||||||
- filament/filament (FILAMENT) - v4
|
- filament/filament (FILAMENT) - v4
|
||||||
- laravel/fortify (FORTIFY) - v1
|
- laravel/fortify (FORTIFY) - v1
|
||||||
- laravel/framework (LARAVEL) - v12
|
- laravel/framework (LARAVEL) - v12
|
||||||
|
- laravel/horizon (HORIZON) - v5
|
||||||
- laravel/pint (PINT) - v1
|
- laravel/pint (PINT) - v1
|
||||||
- laravel/prompts (PROMPTS) - v0
|
- laravel/prompts (PROMPTS) - v0
|
||||||
|
- laravel/pulse (PULSE) - v1
|
||||||
- laravel/reverb (REVERB) - v1
|
- laravel/reverb (REVERB) - v1
|
||||||
- livewire/flux (FLUXUI_FREE) - v2
|
- livewire/flux (FLUXUI_FREE) - v2
|
||||||
- livewire/livewire (LIVEWIRE) - v3
|
- livewire/livewire (LIVEWIRE) - v3
|
||||||
|
|||||||
76
Dockerfile
Normal file
76
Dockerfile
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# 1. Node Builder Stage
|
||||||
|
FROM node:22-alpine AS node-builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY ./ ./
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# 2. Composer Builder Stage
|
||||||
|
FROM php:8.4-cli-alpine AS composer-builder
|
||||||
|
RUN apk add --no-cache unzip
|
||||||
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||||
|
WORKDIR /app
|
||||||
|
COPY composer.json composer.lock ./
|
||||||
|
# Note: ignoring platform requirements since mongo/redis aren't natively in this alpine CLI image
|
||||||
|
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist --ignore-platform-reqs
|
||||||
|
COPY ./ ./
|
||||||
|
RUN composer dump-autoload --optimize --no-dev
|
||||||
|
|
||||||
|
# 3. Production Stage
|
||||||
|
FROM php:8.4-fpm-alpine
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
nginx \
|
||||||
|
supervisor \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
freetype-dev \
|
||||||
|
libzip-dev \
|
||||||
|
icu-dev \
|
||||||
|
git \
|
||||||
|
$PHPIZE_DEPS \
|
||||||
|
linux-headers \
|
||||||
|
openssl-dev
|
||||||
|
|
||||||
|
# Install PHP extensions
|
||||||
|
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||||
|
&& docker-php-ext-install -j$(nproc) \
|
||||||
|
pdo_mysql \
|
||||||
|
gd \
|
||||||
|
zip \
|
||||||
|
intl \
|
||||||
|
bcmath \
|
||||||
|
pcntl \
|
||||||
|
opcache \
|
||||||
|
sockets
|
||||||
|
|
||||||
|
# Install PECL extensions (MongoDB and Redis)
|
||||||
|
RUN pecl install mongodb redis \
|
||||||
|
&& docker-php-ext-enable mongodb redis \
|
||||||
|
&& rm -rf /tmp/pear
|
||||||
|
|
||||||
|
# Copy source code and vendor dependencies
|
||||||
|
COPY . .
|
||||||
|
COPY --from=composer-builder /app/vendor ./vendor
|
||||||
|
COPY --from=node-builder /app/public/build ./public/build
|
||||||
|
|
||||||
|
# Copy configuration files
|
||||||
|
COPY docker/nginx.conf /etc/nginx/http.d/default.conf
|
||||||
|
COPY docker/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf
|
||||||
|
COPY docker/php.ini /usr/local/etc/php/conf.d/production.ini
|
||||||
|
COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
|
||||||
|
# Make entrypoint executable
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
RUN apk del $PHPIZE_DEPS \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
@@ -46,8 +46,10 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
|||||||
- filament/filament (FILAMENT) - v4
|
- filament/filament (FILAMENT) - v4
|
||||||
- laravel/fortify (FORTIFY) - v1
|
- laravel/fortify (FORTIFY) - v1
|
||||||
- laravel/framework (LARAVEL) - v12
|
- laravel/framework (LARAVEL) - v12
|
||||||
|
- laravel/horizon (HORIZON) - v5
|
||||||
- laravel/pint (PINT) - v1
|
- laravel/pint (PINT) - v1
|
||||||
- laravel/prompts (PROMPTS) - v0
|
- laravel/prompts (PROMPTS) - v0
|
||||||
|
- laravel/pulse (PULSE) - v1
|
||||||
- laravel/reverb (REVERB) - v1
|
- laravel/reverb (REVERB) - v1
|
||||||
- livewire/flux (FLUXUI_FREE) - v2
|
- livewire/flux (FLUXUI_FREE) - v2
|
||||||
- livewire/livewire (LIVEWIRE) - v3
|
- livewire/livewire (LIVEWIRE) - v3
|
||||||
|
|||||||
36
app/Providers/HorizonServiceProvider.php
Normal file
36
app/Providers/HorizonServiceProvider.php
Normal 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, [
|
||||||
|
//
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware) {
|
->withMiddleware(function (Middleware $middleware) {
|
||||||
|
$middleware->trustProxies(at: '*');
|
||||||
$middleware->alias([
|
$middleware->alias([
|
||||||
'verify.webhook.secret' => VerifyWebhookSecret::class,
|
'verify.webhook.secret' => VerifyWebhookSecret::class,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ return [
|
|||||||
App\Providers\DynamicMailConfigServiceProvider::class,
|
App\Providers\DynamicMailConfigServiceProvider::class,
|
||||||
App\Providers\Filament\DashPanelProvider::class,
|
App\Providers\Filament\DashPanelProvider::class,
|
||||||
App\Providers\FortifyServiceProvider::class,
|
App\Providers\FortifyServiceProvider::class,
|
||||||
|
App\Providers\HorizonServiceProvider::class,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
"jacobtims/filament-logger": "^1.0",
|
"jacobtims/filament-logger": "^1.0",
|
||||||
"laravel/fortify": "^1.30",
|
"laravel/fortify": "^1.30",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
|
"laravel/horizon": "^5.45",
|
||||||
|
"laravel/pulse": "^1.6",
|
||||||
"laravel/reverb": "^1.8",
|
"laravel/reverb": "^1.8",
|
||||||
"laravel/tinker": "^2.10.1",
|
"laravel/tinker": "^2.10.1",
|
||||||
"livewire/flux": "^2.1.1",
|
"livewire/flux": "^2.1.1",
|
||||||
|
|||||||
284
composer.lock
generated
284
composer.lock
generated
@@ -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": "ac4723b249fb557c0154b1b59679a168",
|
"content-hash": "cd1592da57958973057c2f7e7a9cfb1d",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "anourvalar/eloquent-serialize",
|
"name": "anourvalar/eloquent-serialize",
|
||||||
@@ -1245,6 +1245,61 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-02-05T11:56:58+00:00"
|
"time": "2024-02-05T11:56:58+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/sql-formatter",
|
||||||
|
"version": "1.5.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/sql-formatter.git",
|
||||||
|
"reference": "9563949f5cd3bd12a17d12fb980528bc141c5806"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/9563949f5cd3bd12a17d12fb980528bc141c5806",
|
||||||
|
"reference": "9563949f5cd3bd12a17d12fb980528bc141c5806",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "^14",
|
||||||
|
"ergebnis/phpunit-slow-test-detector": "^2.20",
|
||||||
|
"phpstan/phpstan": "^2.1.31",
|
||||||
|
"phpunit/phpunit": "^10.5.58"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/sql-formatter"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\SqlFormatter\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jeremy Dorn",
|
||||||
|
"email": "jeremy@jeremydorn.com",
|
||||||
|
"homepage": "https://jeremydorn.com/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "a PHP SQL highlighting library",
|
||||||
|
"homepage": "https://github.com/doctrine/sql-formatter/",
|
||||||
|
"keywords": [
|
||||||
|
"highlight",
|
||||||
|
"sql"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/doctrine/sql-formatter/issues",
|
||||||
|
"source": "https://github.com/doctrine/sql-formatter/tree/1.5.4"
|
||||||
|
},
|
||||||
|
"time": "2026-02-08T16:21:46+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "dragonmantank/cron-expression",
|
"name": "dragonmantank/cron-expression",
|
||||||
"version": "v3.6.0",
|
"version": "v3.6.0",
|
||||||
@@ -3072,6 +3127,86 @@
|
|||||||
},
|
},
|
||||||
"time": "2025-11-25T14:46:28+00:00"
|
"time": "2025-11-25T14:46:28+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "laravel/horizon",
|
||||||
|
"version": "v5.45.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/laravel/horizon.git",
|
||||||
|
"reference": "637e065ae0a704288595b896ad1c7c3c9741869b"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/laravel/horizon/zipball/637e065ae0a704288595b896ad1c7c3c9741869b",
|
||||||
|
"reference": "637e065ae0a704288595b896ad1c7c3c9741869b",
|
||||||
|
"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.1"
|
||||||
|
},
|
||||||
|
"time": "2026-03-06T15:31:27+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/pint",
|
"name": "laravel/pint",
|
||||||
"version": "v1.27.1",
|
"version": "v1.27.1",
|
||||||
@@ -3198,6 +3333,94 @@
|
|||||||
},
|
},
|
||||||
"time": "2026-02-06T12:17:10+00:00"
|
"time": "2026-02-06T12:17:10+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "laravel/pulse",
|
||||||
|
"version": "v1.6.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/laravel/pulse.git",
|
||||||
|
"reference": "7cde76c1abe23492edeee7dadec01906cf70427d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/laravel/pulse/zipball/7cde76c1abe23492edeee7dadec01906cf70427d",
|
||||||
|
"reference": "7cde76c1abe23492edeee7dadec01906cf70427d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/sql-formatter": "^1.4.1",
|
||||||
|
"guzzlehttp/promises": "^1.0|^2.0",
|
||||||
|
"illuminate/auth": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/cache": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/config": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/console": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/contracts": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/database": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/events": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/http": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/queue": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/redis": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/routing": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/support": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"illuminate/view": "^10.48.4|^11.0.8|^12.0",
|
||||||
|
"laravel/sentinel": "^1.0",
|
||||||
|
"livewire/livewire": "^3.6.4|^4.0",
|
||||||
|
"nesbot/carbon": "^2.67|^3.0",
|
||||||
|
"php": "^8.1",
|
||||||
|
"symfony/console": "^6.0|^7.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"nunomaduro/collision": "<7.7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"guzzlehttp/guzzle": "^7.7",
|
||||||
|
"mockery/mockery": "^1.0",
|
||||||
|
"orchestra/testbench": "^8.36|^9.15|^10.8",
|
||||||
|
"pestphp/pest": "^2.0|^3.0|^4.0",
|
||||||
|
"pestphp/pest-plugin-laravel": "^2.2|^3.0|^4.0",
|
||||||
|
"phpstan/phpstan": "^1.12.21",
|
||||||
|
"predis/predis": "^1.0|^2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"aliases": {
|
||||||
|
"Pulse": "Laravel\\Pulse\\Facades\\Pulse"
|
||||||
|
},
|
||||||
|
"providers": [
|
||||||
|
"Laravel\\Pulse\\PulseServiceProvider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Laravel\\Pulse\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Taylor Otwell",
|
||||||
|
"email": "taylor@laravel.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.",
|
||||||
|
"homepage": "https://github.com/laravel/pulse",
|
||||||
|
"keywords": [
|
||||||
|
"laravel"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/laravel/pulse/issues",
|
||||||
|
"source": "https://github.com/laravel/pulse"
|
||||||
|
},
|
||||||
|
"time": "2026-02-12T18:51:24+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/reverb",
|
"name": "laravel/reverb",
|
||||||
"version": "v1.8.0",
|
"version": "v1.8.0",
|
||||||
@@ -3277,6 +3500,65 @@
|
|||||||
},
|
},
|
||||||
"time": "2026-02-21T14:37:48+00:00"
|
"time": "2026-02-21T14:37:48+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",
|
||||||
|
|||||||
254
config/horizon.php
Normal file
254
config/horizon.php
Normal 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',
|
||||||
|
],
|
||||||
|
];
|
||||||
244
config/pulse.php
Normal file
244
config/pulse.php
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Laravel\Pulse\Http\Middleware\Authorize;
|
||||||
|
use Laravel\Pulse\Pulse;
|
||||||
|
use Laravel\Pulse\Recorders;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Domain
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the subdomain which the Pulse dashboard will be accessible from.
|
||||||
|
| When set to null, the dashboard will reside under the same domain as
|
||||||
|
| the application. Remember to configure your DNS entries correctly.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'domain' => env('PULSE_DOMAIN'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the path which the Pulse dashboard will be accessible from. Feel
|
||||||
|
| free to change this path to anything you'd like. Note that this won't
|
||||||
|
| affect the path of the internal API that is never exposed to users.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'path' => env('PULSE_PATH', 'pulse'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Master Switch
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration option may be used to completely disable all Pulse
|
||||||
|
| data recorders regardless of their individual configurations. This
|
||||||
|
| provides a single option to quickly disable all Pulse recording.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'enabled' => env('PULSE_ENABLED', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Storage Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration option determines which storage driver will be used
|
||||||
|
| while storing entries from Pulse's recorders. In addition, you also
|
||||||
|
| may provide any options to configure the selected storage driver.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'storage' => [
|
||||||
|
'driver' => env('PULSE_STORAGE_DRIVER', 'database'),
|
||||||
|
|
||||||
|
'trim' => [
|
||||||
|
'keep' => env('PULSE_STORAGE_KEEP', '7 days'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'database' => [
|
||||||
|
'connection' => env('PULSE_DB_CONNECTION'),
|
||||||
|
'chunk' => 1000,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Ingest Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration options determines the ingest driver that will be used
|
||||||
|
| to capture entries from Pulse's recorders. Ingest drivers are great to
|
||||||
|
| free up your request workers quickly by offloading the data storage.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'ingest' => [
|
||||||
|
'driver' => env('PULSE_INGEST_DRIVER', 'storage'),
|
||||||
|
|
||||||
|
'buffer' => env('PULSE_INGEST_BUFFER', 5_000),
|
||||||
|
|
||||||
|
'trim' => [
|
||||||
|
'lottery' => [1, 1_000],
|
||||||
|
'keep' => env('PULSE_INGEST_KEEP', '7 days'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'redis' => [
|
||||||
|
'connection' => env('PULSE_REDIS_CONNECTION'),
|
||||||
|
'chunk' => 1000,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Cache Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration option determines the cache driver that will be used
|
||||||
|
| for various tasks, including caching dashboard results, establishing
|
||||||
|
| locks for events that should only occur on one server and signals.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cache' => env('PULSE_CACHE_DRIVER'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Route Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These middleware will be assigned to every Pulse route, giving you the
|
||||||
|
| chance to add your own middleware to this list or change any of the
|
||||||
|
| existing middleware. Of course, reasonable defaults are provided.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => [
|
||||||
|
'web',
|
||||||
|
Authorize::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pulse Recorders
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following array lists the "recorders" that will be registered with
|
||||||
|
| Pulse, along with their configuration. Recorders gather application
|
||||||
|
| event data from requests and tasks to pass to your ingest driver.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'recorders' => [
|
||||||
|
Laravel\Reverb\Pulse\Recorders\ReverbConnections::class => [
|
||||||
|
'sample_rate' => 1,
|
||||||
|
],
|
||||||
|
|
||||||
|
Laravel\Reverb\Pulse\Recorders\ReverbMessages::class => [
|
||||||
|
'sample_rate' => 1,
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\CacheInteractions::class => [
|
||||||
|
'enabled' => env('PULSE_CACHE_INTERACTIONS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_CACHE_INTERACTIONS_SAMPLE_RATE', 1),
|
||||||
|
'ignore' => [
|
||||||
|
...Pulse::defaultVendorCacheKeys(),
|
||||||
|
],
|
||||||
|
'groups' => [
|
||||||
|
'/^job-exceptions:.*/' => 'job-exceptions:*',
|
||||||
|
// '/:\d+/' => ':*',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\Exceptions::class => [
|
||||||
|
'enabled' => env('PULSE_EXCEPTIONS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_EXCEPTIONS_SAMPLE_RATE', 1),
|
||||||
|
'location' => env('PULSE_EXCEPTIONS_LOCATION', true),
|
||||||
|
'ignore' => [
|
||||||
|
// '/^Package\\\\Exceptions\\\\/',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\Queues::class => [
|
||||||
|
'enabled' => env('PULSE_QUEUES_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_QUEUES_SAMPLE_RATE', 1),
|
||||||
|
'ignore' => [
|
||||||
|
// '/^Package\\\\Jobs\\\\/',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\Servers::class => [
|
||||||
|
'server_name' => env('PULSE_SERVER_NAME', gethostname()),
|
||||||
|
'directories' => explode(':', env('PULSE_SERVER_DIRECTORIES', '/')),
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\SlowJobs::class => [
|
||||||
|
'enabled' => env('PULSE_SLOW_JOBS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_SLOW_JOBS_SAMPLE_RATE', 1),
|
||||||
|
'threshold' => env('PULSE_SLOW_JOBS_THRESHOLD', 1000),
|
||||||
|
'ignore' => [
|
||||||
|
// '/^Package\\\\Jobs\\\\/',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\SlowOutgoingRequests::class => [
|
||||||
|
'enabled' => env('PULSE_SLOW_OUTGOING_REQUESTS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_SLOW_OUTGOING_REQUESTS_SAMPLE_RATE', 1),
|
||||||
|
'threshold' => env('PULSE_SLOW_OUTGOING_REQUESTS_THRESHOLD', 1000),
|
||||||
|
'ignore' => [
|
||||||
|
// '#^http://127\.0\.0\.1:13714#', // Inertia SSR...
|
||||||
|
],
|
||||||
|
'groups' => [
|
||||||
|
// '#^https://api\.github\.com/repos/.*$#' => 'api.github.com/repos/*',
|
||||||
|
// '#^https?://([^/]*).*$#' => '\1',
|
||||||
|
// '#/\d+#' => '/*',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\SlowQueries::class => [
|
||||||
|
'enabled' => env('PULSE_SLOW_QUERIES_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_SLOW_QUERIES_SAMPLE_RATE', 1),
|
||||||
|
'threshold' => env('PULSE_SLOW_QUERIES_THRESHOLD', 1000),
|
||||||
|
'location' => env('PULSE_SLOW_QUERIES_LOCATION', true),
|
||||||
|
'max_query_length' => env('PULSE_SLOW_QUERIES_MAX_QUERY_LENGTH'),
|
||||||
|
'ignore' => [
|
||||||
|
'/(["`])pulse_[\w]+?\1/', // Pulse tables...
|
||||||
|
'/(["`])telescope_[\w]+?\1/', // Telescope tables...
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\SlowRequests::class => [
|
||||||
|
'enabled' => env('PULSE_SLOW_REQUESTS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_SLOW_REQUESTS_SAMPLE_RATE', 1),
|
||||||
|
'threshold' => env('PULSE_SLOW_REQUESTS_THRESHOLD', 1000),
|
||||||
|
'ignore' => [
|
||||||
|
'#^/'.env('PULSE_PATH', 'pulse').'$#', // Pulse dashboard...
|
||||||
|
'#^/telescope#', // Telescope dashboard...
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\UserJobs::class => [
|
||||||
|
'enabled' => env('PULSE_USER_JOBS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_USER_JOBS_SAMPLE_RATE', 1),
|
||||||
|
'ignore' => [
|
||||||
|
// '/^Package\\\\Jobs\\\\/',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
Recorders\UserRequests::class => [
|
||||||
|
'enabled' => env('PULSE_USER_REQUESTS_ENABLED', true),
|
||||||
|
'sample_rate' => env('PULSE_USER_REQUESTS_SAMPLE_RATE', 1),
|
||||||
|
'ignore' => [
|
||||||
|
'#^/'.env('PULSE_PATH', 'pulse').'$#', // Pulse dashboard...
|
||||||
|
'#^/telescope#', // Telescope dashboard...
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Laravel\Pulse\Support\PulseMigration;
|
||||||
|
|
||||||
|
return new class extends PulseMigration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
if (! $this->shouldRun()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::create('pulse_values', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedInteger('timestamp');
|
||||||
|
$table->string('type');
|
||||||
|
$table->mediumText('key');
|
||||||
|
match ($this->driver()) {
|
||||||
|
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||||
|
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||||
|
'sqlite' => $table->string('key_hash'),
|
||||||
|
};
|
||||||
|
$table->mediumText('value');
|
||||||
|
|
||||||
|
$table->index('timestamp'); // For trimming...
|
||||||
|
$table->index('type'); // For fast lookups and purging...
|
||||||
|
$table->unique(['type', 'key_hash']); // For data integrity and upserts...
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('pulse_entries', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedInteger('timestamp');
|
||||||
|
$table->string('type');
|
||||||
|
$table->mediumText('key');
|
||||||
|
match ($this->driver()) {
|
||||||
|
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||||
|
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||||
|
'sqlite' => $table->string('key_hash'),
|
||||||
|
};
|
||||||
|
$table->bigInteger('value')->nullable();
|
||||||
|
|
||||||
|
$table->index('timestamp'); // For trimming...
|
||||||
|
$table->index('type'); // For purging...
|
||||||
|
$table->index('key_hash'); // For mapping...
|
||||||
|
$table->index(['timestamp', 'type', 'key_hash', 'value']); // For aggregate queries...
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('pulse_aggregates', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedInteger('bucket');
|
||||||
|
$table->unsignedMediumInteger('period');
|
||||||
|
$table->string('type');
|
||||||
|
$table->mediumText('key');
|
||||||
|
match ($this->driver()) {
|
||||||
|
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||||
|
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||||
|
'sqlite' => $table->string('key_hash'),
|
||||||
|
};
|
||||||
|
$table->string('aggregate');
|
||||||
|
$table->decimal('value', 20, 2);
|
||||||
|
$table->unsignedInteger('count')->nullable();
|
||||||
|
|
||||||
|
$table->unique(['bucket', 'period', 'type', 'aggregate', 'key_hash']); // Force "on duplicate update"...
|
||||||
|
$table->index(['period', 'bucket']); // For trimming...
|
||||||
|
$table->index('type'); // For purging...
|
||||||
|
$table->index(['period', 'type', 'aggregate', 'bucket']); // For aggregate queries...
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('pulse_values');
|
||||||
|
Schema::dropIfExists('pulse_entries');
|
||||||
|
Schema::dropIfExists('pulse_aggregates');
|
||||||
|
}
|
||||||
|
};
|
||||||
34
docker/entrypoint.sh
Normal file
34
docker/entrypoint.sh
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Starting iMail container initialization..."
|
||||||
|
|
||||||
|
# Ensure storage directories exist
|
||||||
|
mkdir -p /var/www/html/storage/framework/cache/data
|
||||||
|
mkdir -p /var/www/html/storage/framework/sessions
|
||||||
|
mkdir -p /var/www/html/storage/framework/views
|
||||||
|
mkdir -p /var/www/html/storage/logs
|
||||||
|
mkdir -p /var/www/html/storage/app/public
|
||||||
|
mkdir -p /var/www/html/bootstrap/cache
|
||||||
|
|
||||||
|
# Fix permissions
|
||||||
|
chown -R www-data:www-data /var/www/html/storage
|
||||||
|
chown -R www-data:www-data /var/www/html/bootstrap/cache
|
||||||
|
|
||||||
|
# Cache configuration, routes, views, events
|
||||||
|
echo "Caching configuration and routes..."
|
||||||
|
php artisan config:cache
|
||||||
|
php artisan route:cache
|
||||||
|
php artisan view:cache
|
||||||
|
php artisan event:cache
|
||||||
|
|
||||||
|
# Create storage symlink
|
||||||
|
php artisan storage:link
|
||||||
|
|
||||||
|
# Run migrations automatically
|
||||||
|
echo "Running migrations..."
|
||||||
|
php artisan migrate --force
|
||||||
|
|
||||||
|
echo "Initialization complete. Starting Supervisord..."
|
||||||
|
# Execute supervisord in the foreground
|
||||||
|
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||||
71
docker/nginx.conf
Normal file
71
docker/nginx.conf
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
root /var/www/html/public;
|
||||||
|
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
add_header X-Content-Type-Options "nosniff";
|
||||||
|
|
||||||
|
index index.php;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
|
||||||
|
client_max_body_size 64M;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
|
||||||
|
|
||||||
|
# Laravel routes
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pulse Dashboard
|
||||||
|
location = /pulse {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Horizon Dashboard
|
||||||
|
location = /horizon {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reverb WebSocket Proxy
|
||||||
|
# The trailing slash on proxy_pass strips the /_ws prefix:
|
||||||
|
# /_ws/app/{key} → /app/{key}
|
||||||
|
location /_ws/ {
|
||||||
|
proxy_pass http://127.0.0.1:8080/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header Scheme $scheme;
|
||||||
|
proxy_set_header SERVER_PORT $server_port;
|
||||||
|
proxy_set_header REMOTE_ADDR $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "Upgrade";
|
||||||
|
proxy_read_timeout 60m;
|
||||||
|
proxy_connect_timeout 60m;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pass PHP scripts to FastCGI server
|
||||||
|
location ~ \.php$ {
|
||||||
|
fastcgi_pass 127.0.0.1:9000;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_hide_header X-Powered-By;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public, no-transform";
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\.(?!well-known).* {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
docker/php-fpm.conf
Normal file
21
docker/php-fpm.conf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[global]
|
||||||
|
error_log = /dev/stderr
|
||||||
|
|
||||||
|
[www]
|
||||||
|
user = www-data
|
||||||
|
group = www-data
|
||||||
|
|
||||||
|
listen = 127.0.0.1:9000
|
||||||
|
|
||||||
|
pm = dynamic
|
||||||
|
pm.max_children = 50
|
||||||
|
pm.start_servers = 5
|
||||||
|
pm.min_spare_servers = 5
|
||||||
|
pm.max_spare_servers = 35
|
||||||
|
pm.max_requests = 500
|
||||||
|
|
||||||
|
clear_env = no
|
||||||
|
catch_workers_output = yes
|
||||||
|
decorate_workers_output = no
|
||||||
|
|
||||||
|
access.log = /dev/null
|
||||||
21
docker/php.ini
Normal file
21
docker/php.ini
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[PHP]
|
||||||
|
expose_php = Off
|
||||||
|
display_errors = Off
|
||||||
|
display_startup_errors = Off
|
||||||
|
log_errors = On
|
||||||
|
error_log = /dev/stderr
|
||||||
|
memory_limit = 256M
|
||||||
|
upload_max_filesize = 64M
|
||||||
|
post_max_size = 64M
|
||||||
|
max_execution_time = 60
|
||||||
|
max_input_time = 60
|
||||||
|
variables_order = "EGPCS"
|
||||||
|
|
||||||
|
[opcache]
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.memory_consumption=256
|
||||||
|
opcache.interned_strings_buffer=16
|
||||||
|
opcache.max_accelerated_files=20000
|
||||||
|
opcache.validate_timestamps=0
|
||||||
|
opcache.save_comments=1
|
||||||
|
opcache.fast_shutdown=1
|
||||||
83
docker/supervisord.conf
Normal file
83
docker/supervisord.conf
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
logfile=/dev/null
|
||||||
|
logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:php-fpm]
|
||||||
|
command=php-fpm --nodaemonize --fpm-config /usr/local/etc/php-fpm.d/www.conf
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=5
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:nginx]
|
||||||
|
command=nginx -g "daemon off;"
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=10
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:horizon]
|
||||||
|
command=php /var/www/html/artisan horizon
|
||||||
|
user=www-data
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=15
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
stopwaitsecs=3600
|
||||||
|
|
||||||
|
[program:scheduler]
|
||||||
|
command=/bin/sh -c "while sleep 60; do php /var/www/html/artisan schedule:run; done"
|
||||||
|
user=www-data
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=20
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:reverb]
|
||||||
|
command=php /var/www/html/artisan reverb:start --host=0.0.0.0 --port=8080
|
||||||
|
user=www-data
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=25
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:pulse-check]
|
||||||
|
command=php /var/www/html/artisan pulse:check
|
||||||
|
user=www-data
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=30
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
stopwaitsecs=3600
|
||||||
|
|
||||||
|
[program:pulse-work]
|
||||||
|
command=php /var/www/html/artisan pulse:work
|
||||||
|
user=www-data
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=35
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
stopwaitsecs=3600
|
||||||
BIN
install.log
Normal file
BIN
install.log
Normal file
Binary file not shown.
@@ -10,6 +10,7 @@ if (document.querySelector('[data-requires-reverb]')) {
|
|||||||
wsHost: import.meta.env.VITE_REVERB_HOST,
|
wsHost: import.meta.env.VITE_REVERB_HOST,
|
||||||
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
|
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
|
||||||
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
|
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
|
||||||
|
wsPath: import.meta.env.VITE_REVERB_PATH ?? '',
|
||||||
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
|
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
|
||||||
enabledTransports: ['ws', 'wss'],
|
enabledTransports: ['ws', 'wss'],
|
||||||
});
|
});
|
||||||
|
|||||||
19
resources/views/vendor/pulse/dashboard.blade.php
vendored
Normal file
19
resources/views/vendor/pulse/dashboard.blade.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<x-pulse>
|
||||||
|
<livewire:pulse.servers cols="full" />
|
||||||
|
|
||||||
|
<livewire:pulse.usage cols="4" rows="2" />
|
||||||
|
|
||||||
|
<livewire:pulse.queues cols="4" />
|
||||||
|
|
||||||
|
<livewire:pulse.cache cols="4" />
|
||||||
|
|
||||||
|
<livewire:pulse.slow-queries cols="8" />
|
||||||
|
|
||||||
|
<livewire:pulse.exceptions cols="6" />
|
||||||
|
|
||||||
|
<livewire:pulse.slow-requests cols="6" />
|
||||||
|
|
||||||
|
<livewire:pulse.slow-jobs cols="6" />
|
||||||
|
|
||||||
|
<livewire:pulse.slow-outgoing-requests cols="6" />
|
||||||
|
</x-pulse>
|
||||||
@@ -9,3 +9,4 @@ Artisan::command('inspire', function (): void {
|
|||||||
})->purpose('Display an inspiring quote');
|
})->purpose('Display an inspiring quote');
|
||||||
|
|
||||||
Schedule::command('mailboxes:cleanup')->everyMinute();
|
Schedule::command('mailboxes:cleanup')->everyMinute();
|
||||||
|
Schedule::command('horizon:snapshot')->everyFiveMinutes();
|
||||||
|
|||||||
Reference in New Issue
Block a user