start-point/etcd-php
PHP client for etcd v3 with a simple API for KV operations, leases, and authentication/roles/users. Install via Composer and connect to an etcd endpoint to put/get/delete keys, query prefixes, manage leases, and handle auth tokens.
composer require start-point/etcd-php
AppServiceProvider):
use Etcd\Client;
public function register()
{
$this->app->singleton(Client::class, function ($app) {
return new Client(config('etcd.host'), config('etcd.port'));
});
}
config/services.php:
'etcd' => [
'host' => env('ETCD_HOST', '127.0.0.1'),
'port' => env('ETCD_PORT', 2379),
'timeout' => 2.0, // Optional: connection timeout in seconds
],
$client = app(Client::class);
$redisHost = $client->get('config/redis/host');
put(), get(), and del() for basic configuration management.grant() and keepAlive() for distributed locks or ephemeral data.authEnable() and authenticate() if Etcd requires RBAC.// In a service provider
public function boot()
{
$client = app(Client::class);
config(['database.connections.etcd.host' => $client->get('config/database/host')]);
}
// Note: Watch functionality may not be fully supported in this package.
// Use polling as a fallback:
$lastVersion = null;
while (true) {
$value = $client->get('config/feature_flags/enabled', ['version' => $lastVersion]);
if ($value['version'] !== $lastVersion) {
$lastVersion = $value['version'];
// Update feature flags in Laravel
}
sleep(1); // Poll every second
}
// Register a service
$client->put('/services/api/v1', json_encode([
'host' => '10.0.0.1',
'port' => 8000,
'status' => 'healthy',
]));
// Discover services
$services = $client->getKeysWithPrefix('/services/');
$apiService = json_decode($client->get('/services/api/v1'), true);
$client = app(Client::class);
$leaseId = $client->grant(10); // 10-second lease
try {
// Acquire lock by setting a key with the lease
$client->put('/locks/migration', 'locked', ['lease' => $leaseId]);
// Critical section
$this->runMigration();
} finally {
// Release lock by deleting the key
$client->del('/locks/migration');
$client->revoke($leaseId);
}
$client = app(Client::class);
$client->authEnable();
$token = $client->authenticate('admin', 'securepassword');
$client->setToken($token);
// Grant permissions to a role
$client->grantRolePermission('admin', Client::PERMISSION_READWRITE, '/config/*');
Extend Laravel’s cache system to use Etcd:
use Illuminate\Contracts\Cache\Store;
class EtcdCacheStore implements Store {
protected $client;
public function __construct(Client $client) {
$this->client = $client;
}
public function get($key, $default = null) {
$value = $this->client->get("cache/{$key}");
return $value ? json_decode($value, true) : $default;
}
public function put($key, $value, $seconds) {
$this->client->put("cache/{$key}", json_encode($value), [
'lease' => $this->client->grant($seconds)
]);
}
// Implement other cache methods...
}
Register in config/cache.php:
'etcd' => [
'driver' => 'etcd',
'key' => env('CACHE_ETCD_KEY', 'default'),
],
Create a facade for Etcd-backed configs:
// app/Facades/EtcdConfig.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class EtcdConfig extends Facade {
protected static function getFacadeAccessor() {
return 'etcd.config';
}
}
Bind in AppServiceProvider:
$this->app->bind('etcd.config', function ($app) {
return new class($app) {
public function get($key, $default = null) {
$client = $app['Etcd\Client'];
$value = $client->get("config/{$key}");
return $value ? json_decode($value, true) : $default;
}
};
});
Usage:
$redisHost = EtcdConfig::get('redis.host');
Prevent duplicate jobs using Etcd leases:
use Illuminate\Bus\Queueable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Etcd\Client;
class ProcessPayment implements ShouldQueue {
use InteractsWithQueue;
public function handle() {
$client = app(Client::class);
$leaseId = $client->grant(300); // 5-minute lease
try {
// Try to acquire lock
$locked = $client->put('/jobs/process_payment', 'locked', [
'lease' => $leaseId,
'prev_kv' => true
]);
if ($locked['prev_kv']) {
// Another instance is processing; skip
return;
}
// Process payment
$this->executePayment();
} finally {
$client->del('/jobs/process_payment');
$client->revoke($leaseId);
}
}
}
Stale Codebase:
No Native Watch Support:
etcdctl watch).Authentication Quirks:
authenticate() method may not support all Etcd auth flows (e.g., JWT tokens).Lease Management:
keepAlive), which can fail silently.Error Handling:
$response = $client->get('nonexistent_key');
if (isset($response['error'])) {
// Handle error
}
Performance Overhead:
etcd3 (gRPC-based).No Transaction Support:
compareAndSwap or use application-level locks.etcd --logger=zap --log-level=DEBUG
How can I help you explore Laravel packages today?