Laravel-Entwicklung
Laravel-Anwendungen – entwickelt und zuverlässig betrieben.
Vom ersten Model bis zu den Queue-Workern, den Deployments und dem Upgrade Jahre später – geschrieben, gehostet und betreut von einem einzigen Team.
Ein Release, wie es auf dem Server aussieht
Jede Laravel-Anwendung, die wir betreiben, geht auf dieselbe Weise live: getestet, gebaut, gecacht und ohne eine Sekunde Ausfallzeit umgeschaltet.
01ci ~/app $ php artisan test PASS Tests\Feature\CheckoutTest ✓ a paid order queues the invoice ✓ a declined card never marks the order paid PASS Tests\Unit\VatTest ✓ vat is added once, on the total 02app ~/releases/1400 $ composer install --no-dev --optimize-autoloaderInstalling dependencies from lock fileGenerating optimized autoload files 03app ~/releases/1400 $ php artisan migrate --force INFO Running migrations. 2026_09_27_090000_add_due_date_to_invoices ....... DONE 04app ~/releases/1400 $ php artisan optimize INFO Caching framework bootstrap, configuration, and metadata. config ...................................... DONE events ...................................... DONE routes ...................................... DONE views ....................................... DONE 05app ~/releases/1400 $ ln -sfn ~/releases/1400 ~/current06app ~/releases/1400 $ php artisan horizon:terminate && php artisan octane:reload 07app ~/releases/1400 $ sudo supervisorctl statushorizon RUNNING pid 48211, uptime 0:00:09octane RUNNING pid 31877, uptime 6 days, 2:14:51 08app ~/releases/1400 $ php artisan schedule:list */5 * * * * php artisan horizon:snapshot ... Next Due: 3 minutes from now 0 2 * * * php artisan model:prune ........ Next Due: 9 hours from now 0 9 * * * php artisan invoices:remind .... Next Due: 16 hours from now
Zuerst die Tests
Die Tests laufen, bevor irgendetwas den Server erreicht. Ein einziger fehlgeschlagener Test stoppt das Release.
Abhängigkeiten
Nur aus der Lock-Datei installiert, ohne Entwicklungspakete und mit optimiertem Autoloader.
Migrationen
So geschrieben, dass der laufende Code auch mit dem neuen Schema funktioniert, während das Release umgeschaltet wird.
Caches
Konfiguration, Events, Routen und Views werden gecacht. Ab hier wird die Umgebungsdatei gar nicht mehr gelesen – deshalb gehört env() ausschließlich in die Konfigurationsdateien.
Die Umschaltung
Ein Link wird umgesetzt, und das neue Release ist live. Das vorherige bleibt für einen Rollback auf der Festplatte.
Worker
Horizon arbeitet die laufenden Jobs noch ab und startet dann mit dem neuen Code neu; Octane lädt seine Worker auf dieselbe Weise neu.
Überwacht
Supervisor hält Horizon und Octane am Laufen und startet jeden der beiden neu, falls er stoppt.
Der Scheduler
Eine einzige Cron-Zeile führt jede geplante Aufgabe aus. Das hier läuft als Nächstes.
Vom Klick bis zum erledigten Job
Die langsame Arbeit verlässt die Anfrage. Der Kunde erhält sofort eine Antwort, und ein Worker erledigt den Rest im Hintergrund.
-
01 · Anfrage
POST /checkoutDer Kunde bezahlt
Der Controller validiert die Bestellung, speichert sie und antwortet sofort. Hier passiert nichts Langsames.
-
02 · Job
PayOrder::dispatch()Der langsame Teil wird zum Job
Erst nach dem Commit der Datenbank abgesetzt, damit ein Worker nie eine Bestellung aufgreift, die zurückgerollt wurde.
-
03 · Queue
redis · paymentsEr wartet in seiner eigenen Queue
Zahlungen haben ihre eigene Queue, damit ein langer Export sie nie aufhält.
-
04 · Worker
horizon · supervisorEin Worker übernimmt ihn
Mit Timeout, Wiederholungen mit jedes Mal längerer Wartezeit und einer Grenze dafür, wie viele gleichzeitig laufen.
-
05 · Benachrichtigung
OrderPaid → mail, databaseAlle werden informiert
Der Kunde erhält die Rechnung per E-Mail, und die Bestellung erscheint in Ihrem Dashboard als bezahlt.
failed_jobs
Ein Job, der keine Wiederholungen mehr übrig hat, wird mit seinem Fehler aufbewahrt, und wir werden alarmiert. Sobald die Ursache behoben ist, wird er erneut ausgeführt – er geht nie stillschweigend verloren.
Die ganze Anwendung, nicht nur der Server
Unser Team bringt fünfundzwanzig Jahre PHP-Erfahrung in jedes Laravel-Projekt ein, vom ersten Model bis zum Upgrade Jahre später.
Entwickeln
Die Anwendung selbst.
- Architektur
- Geschäftslogik in Actions und Services, nicht in Controllern. Form Requests für die Validierung, Policies dafür, wer was darf.
- Eloquent
- Relationen werden vorab geladen, wo eine Seite sie auflistet – so kostet eine Seite wenige Abfragen statt Hunderter. In der Entwicklung löst Lazy Loading einen Fehler aus, damit das Problem früh auffällt.
- Livewire · Inertia
- Livewire, wenn das Team PHP und Blade schreibt; Inertia mit Vue oder React, wenn das Frontend ein eigenes Projekt ist.
- APIs mit Sanctum
- Tokens für mobile Apps und Partner, Cookie-Sessions für Ihr eigenes Frontend und Rate Limits pro Client.
- Pest · PHPUnit
- Tests für jeden Pfad, bei dem Geld fließt oder E-Mails verschickt werden – bei jedem Push ausgeführt, bevor ein Release gebaut wird.
Betreiben
Was sie reaktionsfähig hält.
- Queues und Horizon
- Getrennte Queues für dringende Aufgaben und Massenverarbeitung, jede mit eigenen Workern, Timeouts und Wiederholungen, überwacht im Horizon-Dashboard.
- Der Scheduler
- Eine Cron-Zeile führt jede Aufgabe aus. Aufgaben, die sich nicht überschneiden dürfen oder nur auf einem Server laufen sollen, werden entsprechend markiert.
- Octane
- Swoole, RoadRunner oder FrankenPHP halten die Anwendung zwischen den Anfragen im Speicher. Bevor wir das einschalten, prüfen wir den Code auf Zustand, der von einer Anfrage in die nächste durchsickert.
- Redis
- Cache, Sessions, Queues und Locks auf einem Redis, der aus dem Internet nicht erreichbar ist.
- Supervisor
- Queue-Worker, Horizon und Octane laufen als überwachte Prozesse und werden neu gestartet, wenn sie stoppen, sowie nach jedem Release.
Pflegen
Was sie aktuell hält.
- Deployments ohne Ausfallzeit
- Jedes Release wird in einem eigenen Verzeichnis gebaut und mit einem Link aktiviert. Der Weg zurück ist derselbe Schritt in umgekehrter Richtung.
- Logs und Exceptions
- Tägliche Logdateien, die für eine festgelegte Zeit aufbewahrt werden, und jede Exception wird uns zusammen mit der Anfrage gemeldet, die sie ausgelöst hat.
- Upgrades
- Laravel veröffentlicht jedes Jahr eine neue Hauptversion. Wir heben eine Anwendung Version für Version an, und bei jedem Schritt laufen die Tests erfolgreich durch.
Was wir am ersten Tag einrichten
Bevor der erste Kunde kommt, ist all das auf jedem Laravel-Server, den wir betreiben, bereits eingerichtet.
- Debug-Modus in der Produktion aus, und nur das öffentliche Verzeichnis im Web erreichbar
APP_DEBUG=false - Queue-Worker unter Supervisor, bei jedem Release neu gestartet
supervisord - Eine Cron-Zeile für den Scheduler
* * * * * php artisan schedule:run - Redis für Cache, Sessions und Queues
CACHE_STORE=redis - Konfiguration, Events, Routen und Views bei jedem Release gecacht
php artisan optimize - OPcache aktiv und bei jedem Release zurückgesetzt
opcache.validate_timestamps=0 - Ein PHP-FPM-Pool, passend zum Arbeitsspeicher des Servers
pm.max_children - Releases in eigenen Verzeichnissen, nur einen Schritt vom Rollback entfernt
current → releases/… - Fehlgeschlagene Jobs werden uns gemeldet, statt in einer Tabelle liegen zu bleiben
failed_jobs - Log-Rotation und Benachrichtigungen bei Exceptions
LOG_CHANNEL=daily - Ein nächtliches Datenbank-Backup, außerhalb des Servers gespeichert
backup · offsite - Ein TLS-Zertifikat, das sich selbst erneuert
Let's Encrypt
Ein Release auf der Festplatte
/var/www/example-app
├── current → releases/1400
├── releases/
│ ├── 1400
│ └── 0930
└── shared/
├── .env
└── storage/

Erzählen Sie uns von Ihrer Anwendung
Eine Neuentwicklung, eine Anwendung, die ein Zuhause braucht, oder eine, die auf einer alten Version feststeckt. Jedes Projekt erhält nach einem kurzen Gespräch ein Angebot.