Add app:infra:snapshot command, page reads from var/infra.json
The /admin/infra page was slow because Docker stats API blocks per container. Now a cron (every 5min) generates var/infra.json via app:infra:snapshot, and the page reads the static JSON file instantly. Mount Docker socket in cron container for snapshot access. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -228,6 +228,13 @@
|
||||
job: "docker compose -f /var/www/e-ticket/docker-compose-prod.yml exec -T php php bin/console app:stripe:sync --env=prod >> /var/log/e-ticket-stripe-sync.log 2>&1"
|
||||
user: bot
|
||||
|
||||
- name: Configure infra snapshot cron (every 5 minutes)
|
||||
cron:
|
||||
name: "e-ticket infra snapshot"
|
||||
minute: "*/5"
|
||||
job: "docker compose -f /var/www/e-ticket/docker-compose-prod.yml exec -T php php bin/console app:infra:snapshot --env=prod >> /var/log/e-ticket-infra.log 2>&1"
|
||||
user: bot
|
||||
|
||||
post_tasks:
|
||||
- name: Disable maintenance mode
|
||||
command: make maintenance_off
|
||||
|
||||
@@ -179,8 +179,11 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
container_name: e_ticket_cron
|
||||
restart: unless-stopped
|
||||
group_add:
|
||||
- "${DOCKER_GID:-989}"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
depends_on:
|
||||
pgbouncer:
|
||||
condition: service_healthy
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
0 * * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:monitor:messenger" >> /proc/1/fd/1 && php /app/bin/console app:monitor:messenger --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:monitor:messenger" >> /proc/1/fd/1
|
||||
0 3 * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:meilisearch:check-consistency" >> /proc/1/fd/1 && php /app/bin/console app:meilisearch:check-consistency --fix --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:meilisearch:check-consistency" >> /proc/1/fd/1
|
||||
0 */6 * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:stripe:sync" >> /proc/1/fd/1 && php /app/bin/console app:stripe:sync --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:stripe:sync" >> /proc/1/fd/1
|
||||
*/5 * * * * php /app/bin/console app:infra:snapshot --env=dev >> /proc/1/fd/1 2>&1
|
||||
|
||||
40
src/Command/InfraSnapshotCommand.php
Normal file
40
src/Command/InfraSnapshotCommand.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Service\InfraService;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore Infrastructure snapshot — reads Docker socket, /proc, network
|
||||
*/
|
||||
#[AsCommand(
|
||||
name: 'app:infra:snapshot',
|
||||
description: 'Generate infrastructure stats snapshot to var/infra.json',
|
||||
)]
|
||||
class InfraSnapshotCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private InfraService $infra,
|
||||
#[Autowire('%kernel.project_dir%')] private string $projectDir,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$data = $this->infra->getAll();
|
||||
$data['generated_at'] = (new \DateTimeImmutable())->format(\DateTimeInterface::ATOM);
|
||||
|
||||
$path = $this->projectDir.'/var/infra.json';
|
||||
file_put_contents($path, json_encode($data, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$output->writeln(sprintf('Snapshot written to %s (%d bytes)', $path, filesize($path)));
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -649,9 +649,21 @@ class AdminController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route('/infra', name: 'app_admin_infra', methods: ['GET'])]
|
||||
public function infra(\App\Service\InfraService $infra): Response
|
||||
public function infra(#[Autowire('%kernel.project_dir%')] string $projectDir): Response
|
||||
{
|
||||
return $this->render('admin/infra.html.twig', $infra->getAll());
|
||||
$path = $projectDir.'/var/infra.json';
|
||||
if (!file_exists($path)) {
|
||||
return $this->render('admin/infra.html.twig', [
|
||||
'snapshot_missing' => true,
|
||||
'server' => [], 'containers' => [], 'redis_global' => ['connected' => false],
|
||||
'redis_dbs' => [], 'postgres' => ['connected' => false], 'pgbouncer' => ['connected' => false],
|
||||
'generated_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents($path), true) ?? [];
|
||||
|
||||
return $this->render('admin/infra.html.twig', $data);
|
||||
}
|
||||
|
||||
#[Route('/organisateurs/inviter', name: 'app_admin_invite_organizer', methods: ['GET', 'POST'])]
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
{% block title %}Infrastructure{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{% if snapshot_missing is defined and snapshot_missing %}
|
||||
<div class="admin-card mb-4">
|
||||
<p class="text-sm font-bold text-yellow-600">Aucun snapshot disponible. Lancez <code class="bg-gray-100 px-1">php bin/console app:infra:snapshot</code></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if generated_at is defined and generated_at %}
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<p class="text-[10px] font-black uppercase tracking-widest text-gray-400">Derniere mise a jour : {{ generated_at|date('d/m/Y H:i:s') }}</p>
|
||||
<a href="{{ path('app_admin_infra') }}" class="text-[10px] font-black uppercase tracking-widest text-gray-400 hover:text-gray-600">Rafraichir</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="grid grid-cols-1 xl:grid-cols-4 gap-4 min-h-[calc(100vh-80px)]">
|
||||
|
||||
{# ── COL 1: Serveur ────────────────────────────────── #}
|
||||
|
||||
Reference in New Issue
Block a user