bluefly / alternative_services
Service abstraction layer for flexible dependency injection and service swapping
Requires
- php: >=8.1
- drupal/core: ^10.3 || ^11
- drupal/health_check: ^3.0
- drupal/monitoring: ^1.0
- drupal/service_container: ^2.0
Suggests
- drupal/memcache: Memcached backend for distributed service caching
- drupal/redis: Redis caching backend for high-performance service caching
- drupal/varnish: Varnish reverse proxy for edge caching
README
Simple service discovery and configuration management using native Drupal patterns.
Overview
The Alternative Services module provides a unified interface for managing external services, APIs, and development tools in Drupal. It offers intelligent service discovery, health monitoring, and automatic failover capabilities, making it easier to build resilient applications that can adapt to service availability.
Features
- Service Registry: Centralized configuration for all external services
- Health Monitoring: Real-time availability checks with configurable intervals
- Intelligent Failover: Automatic switching to alternative services when primary fails
- DDEV Integration: Native UI for managing DDEV addons and services
- AI-Powered Discovery: Automatically discover compatible services in your environment
- Multi-Service Support: Cache, search, queue, storage, and development tools
- Performance Tracking: Monitor service response times and reliability
- Event System: React to service status changes in real-time
Requirements
- Drupal 10.4 or higher / Drupal 11
- PHP 8.1 or higher
Suggested Modules
- Redis (
drupal/redis
) - For Redis cache backend - Memcache (
drupal/memcache
) - For Memcache integration - Queue UI (
drupal/queue_ui
) - For queue service monitoring - Devel (
drupal/devel
) - For development tools integration
Installation
Install via Composer:
composer require bluefly/alternative_services
Enable the module:
drush en alternative_services
Configure services at
/admin/config/development/alternative-services
Service Types
Cache Services
Configure multiple cache backends with automatic failover:
- Redis (primary)
- Memcache (fallback)
- Database (emergency)
- Varnish (HTTP cache)
Search Services
Manage search providers with health monitoring:
- Elasticsearch
- Apache Solr
- Meilisearch
- Database fallback
Queue Services
Queue backend management:
- RabbitMQ
- Beanstalkd
- AWS SQS
- Database queues
Storage Services
External storage configuration:
- Amazon S3
- MinIO
- Local filesystem
- FTP/SFTP
Development Tools
DDEV addon management and debugging services:
- Mailhog
- phpMyAdmin
- Elasticsearch Head
- Redis Commander
Usage
Basic Service Registration
// Get the service provider
$provider = \Drupal::service('alternative_services.provider');
// Register a cache service with alternatives
$provider->registerService('cache', [
'primary' => [
'type' => 'redis',
'host' => 'redis',
'port' => 6379,
'password' => NULL,
],
'fallback' => [
'type' => 'memcache',
'host' => 'memcached',
'port' => 11211,
],
'emergency' => [
'type' => 'database',
'table' => 'cache',
]
]);
Using Services with Automatic Failover
// Get a service (automatically uses first available)
$cache = \Drupal::service('alternative_services.provider')
->getService('cache');
// Service will automatically failover if primary fails
try {
$cache->set('my_key', 'my_value');
} catch (ServiceUnavailableException $e) {
// All services are down
\Drupal::logger('alternative_services')->error('No cache service available');
}
Health Monitoring
// Check service health
$health = \Drupal::service('alternative_services.health_monitor');
$status = $health->checkService('elasticsearch');
if (!$status->isHealthy()) {
// Service is down, failover will occur automatically
\Drupal::logger('alternative_services')->warning(
'Service @service is unhealthy: @reason',
['@service' => 'elasticsearch', '@reason' => $status->getReason()]
);
}
DDEV Integration
The module provides a UI for DDEV addon management:
- Navigate to
/admin/config/development/alternative-services/ddev
- Browse available DDEV addons
- Click "Install" to add services to your DDEV environment
- Monitor service health from the dashboard
AI-Powered Service Discovery
// Discover available services
$discovery = \Drupal::service('alternative_services.discovery');
$services = $discovery->discover(['type' => 'cache']);
foreach ($services as $service) {
// Automatically detected services in your environment
print $service['name'] . ' at ' . $service['host'] . ':' . $service['port'];
}
Configuration
Global Settings
Configure at /admin/config/development/alternative-services/settings
:
- Health Check Interval: How often to check service health (default: 60 seconds)
- Connection Timeout: Maximum time to wait for service response (default: 5 seconds)
- Retry Attempts: Number of retries before failover (default: 3)
- Failover Strategy: Round-robin, priority, or random selection
Per-Service Configuration
Each service type can have specific settings:
# In alternative_services.settings.yml
elasticsearch:
health_check_interval: 30
connection_timeout: 10
retry_attempts: 2
failover_strategy: priority
Drush Commands
# List all configured services
drush as:list
# Check health of all services
drush as:health-check
# Check specific service
drush as:health-check --service=elasticsearch
# Discover services in environment
drush as:discover
# Discover specific service type
drush as:discover --type=cache
# Force service failover
drush as:failover cache
# Reset service to primary
drush as:reset cache
Events
The module dispatches events for service status changes:
use Drupal\alternative_services\Event\ServiceStatusEvent;
// Subscribe to service events
class MyEventSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
ServiceStatusEvent::SERVICE_DOWN => 'onServiceDown',
ServiceStatusEvent::SERVICE_UP => 'onServiceUp',
ServiceStatusEvent::SERVICE_FAILOVER => 'onServiceFailover',
];
}
public function onServiceDown(ServiceStatusEvent $event) {
// React to service going down
$service = $event->getService();
\Drupal::logger('my_module')->error('Service @service is down',
['@service' => $service->getName()]
);
}
}
Extending the Module
Custom Service Types
namespace Drupal\my_module\Plugin\AlternativeService;
use Drupal\alternative_services\Plugin\AlternativeServiceBase;
/**
* @AlternativeService(
* id = "my_service",
* label = @Translation("My Custom Service"),
* description = @Translation("Custom service implementation")
* )
*/
class MyService extends AlternativeServiceBase {
public function checkHealth() {
// Implement health check
return $this->ping($this->configuration['host']);
}
public function connect() {
// Establish connection
}
}
Troubleshooting
Service Not Failing Over
- Check health check interval isn't too long
- Verify fallback services are configured
- Check logs for connection errors
- Ensure service credentials are correct
DDEV Addon Installation Fails
- Verify DDEV is running (
ddev status
) - Check DDEV version compatibility
- Review DDEV logs (
ddev logs
) - Ensure proper permissions
Performance Considerations
- Health checks run asynchronously to avoid blocking
- Failed services are cached to prevent repeated connection attempts
- Use appropriate health check intervals based on service criticality
- Consider using local services (Redis, Memcache) for better performance
Support
- Issue Queue: https://github.com/bluefly/alternative_services/issues
- Documentation: https://docs.bluefly.dev/alternative-services
- Packagist: https://packagist.org/packages/bluefly/alternative_services
License
This project is licensed under the GPL-2.0-or-later license.