chameleon-system/sanitycheck-bundle
Installation
composer require chameleon-system/sanitycheck-bundle
Enable the bundle in config/bundles.php:
return [
// ...
ChameleonSystem\SanityCheckBundle\SanityCheckBundle::class => ['all' => true],
];
Define a Basic Check
Create a custom check class (e.g., src/Check/MyDiskSpaceCheck.php):
namespace App\Check;
use SanityCheck\Check\CheckInterface;
class MyDiskSpaceCheck implements CheckInterface
{
public function check(): bool
{
$freeSpace = disk_free_space('/');
return $freeSpace > 1024 * 1024 * 1024; // At least 1GB free
}
}
Register the Check
Add it to the container in config/services.yaml:
services:
App\Check\MyDiskSpaceCheck:
tags: ['sanitycheck.check']
Run Checks via CLI Execute checks programmatically or via a command:
php bin/console sanitycheck:run
Use SanityCheck in a pre-deployment hook (e.g., deploy.php):
use Symfony\Component\HttpKernel\KernelInterface;
use SanityCheck\SanityCheck;
$kernel = new AppKernel('prod', false);
$kernel->boot();
$sanityCheck = new SanityCheck($kernel->getContainer());
$results = $sanityCheck->runChecks();
if (!$results->isValid()) {
throw new \RuntimeException('Sanity checks failed: ' . $results->getErrors());
}
Pre-Request Checks (Symfony Middleware) Use middleware to validate system state before processing requests:
namespace App\Middleware;
use SanityCheck\SanityCheck;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class SanityCheckMiddleware
{
public function __invoke(HttpKernelInterface $kernel, Response $response)
{
$sanityCheck = new SanityCheck($kernel->getContainer());
$results = $sanityCheck->runChecks(['disk_space', 'database_connection']);
if (!$results->isValid()) {
return new Response('System checks failed: ' . $results->getErrors(), 503);
}
return $kernel->handle($request, $response->create($kernel->getRequest()));
}
}
Scheduled Checks (Cron Jobs)
Integrate with Laravel’s task scheduler (app/Console/Kernel.php):
protected function schedule(Schedule $schedule)
{
$schedule->command('sanitycheck:run --format=json')
->dailyAt('3:00')
->emailOutputTo('admin@example.com');
}
Dynamic Check Registration Register checks conditionally (e.g., based on environment):
# config/packages/sanitycheck.yaml
sanitycheck:
checks:
- '%kernel.environment% == "prod" ? App\Check\ProdChecks : App\Check\DevChecks'
Check Dependencies Chain checks to enforce logical dependencies:
class DatabaseCheck implements CheckInterface
{
public function check(): bool
{
return DB::connection()->getPdo() !== null;
}
}
class CacheCheck implements CheckInterface
{
public function check(): bool
{
return Cache::store('file')->get('test') === 'test';
}
}
Artisan commands to trigger checks:
php artisan sanitycheck:run --checks="database,queue"
$results = $sanityCheck->runChecks();
\Log::info('SanityCheck Results', ['valid' => $results->isValid(), 'errors' => $results->getErrors()]);
return response()->json([
'status' => $results->isValid() ? 'healthy' : 'unhealthy',
'errors' => $results->getErrors(),
]);
Check Order Matters
# config/services.yaml
services:
App\Check\DatabaseCheck:
tags: ['sanitycheck.check', { priority: 10 }] # Lower priority = runs first
Performance Overhead
Symfony vs. Laravel Quirks
app() helper or bind services explicitly:
$sanityCheck = new SanityCheck(app());
sanitycheck. (e.g., sanitycheck.checks).False Positives
file_permissions may fail intermittently (e.g., due to temporary locks). Add retries or grace periods:
public function check(): bool
{
return file_exists('/tmp/required-file') && !is_writable('/tmp/required-file');
}
--verbose for detailed logs:
php bin/console sanitycheck:run --verbose
php bin/console sanitycheck:run --checks="App\Check\MyDiskSpaceCheck"
sanitycheck:debug command to inspect registered checks.Custom Check Formats
Extend SanityCheck\Result\ResultInterface to add custom metadata:
class CustomResult implements ResultInterface
{
public function getSeverity(): string
{
return $this->severity ?? 'warning';
}
}
Event Dispatching
Trigger events when checks pass/fail (e.g., using Symfony’s EventDispatcher):
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
$dispatcher = new EventDispatcher();
$dispatcher->addListener('sanitycheck.failed', function ($event) {
// Send alert (e.g., Slack, PagerDuty)
});
Check Templates Create reusable check templates for common scenarios (e.g., database, queue, storage):
abstract class BaseCheck implements CheckInterface
{
abstract protected function getResource(): string;
public function check(): bool
{
return file_exists($this->getResource());
}
}
Laravel Notifications Integrate with Laravel’s notification system for failed checks:
use Illuminate\Notifications\Notifiable;
class SanityCheckFailed implements ShouldQueue
{
use Notifiable;
public function via($notifiable)
{
return ['database'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line('Sanity check failed: ' . $this->error);
}
}
How can I help you explore Laravel packages today?