kislayphp / discovery
High-performance C++ PHP extension providing service discovery and registration for PHP microservices
Package info
github.com/KislayPHP/discovery
Language:Shell
Type:php-ext
Ext name:ext-kislayphp_discovery
pkg:composer/kislayphp/discovery
Requires
- php: >=8.2
Suggests
- kislayphp/config: Dynamic service configuration
- kislayphp/core: HTTP/HTTPS server foundation
- kislayphp/eventbus: Service change notifications
- kislayphp/gateway: Service-aware API gateway
- kislayphp/metrics: Service health metrics
- kislayphp/queue: Service-aware message queuing
Provides
README
PHP extension for service registration and discovery with instance-level health state.
Concurrency Mode
- Default API mode is synchronous.
- Registry operations (
register,resolve,listInstances, heartbeat/status updates) return immediate values. - Use core async clients (for example
Kislay\Core\AsyncHttp) for non-blocking inter-service HTTP calls.
Version
Current package line: v0.0.4.
Namespace
- Primary classes:
Kislay\Discovery\ServiceRegistryKislay\Discovery\ClientInterface
- Legacy aliases:
KislayPHP\Discovery\ServiceRegistryKislayPHP\Discovery\ClientInterface
Installation
Via PIE:
pie install kislayphp/discovery:0.0.4
Enable in php.ini:
extension=kislayphp_discovery.so
Build from source:
phpize ./configure --enable-kislayphp_discovery make sudo make install
Quick Start
<?php $registry = new Kislay\Discovery\ServiceRegistry(); $registry->setHeartbeatTimeout(30000); // 30 seconds $registry->register('user-service', 'http://127.0.0.1:9001', ['zone' => 'az-1'], 'user-1'); $registry->register('user-service', 'http://127.0.0.1:9002', ['zone' => 'az-2'], 'user-2'); $url = $registry->resolve('user-service'); $instances = $registry->listInstances('user-service'); var_dump($url, $instances);
Documentation
- Basic docs remain in this repository.
- Full detailed docs are maintained on the site: https://skelves.com/kislayphp/docs
- Local docs route:
http://localhost:5180/kislayphp/docs
Standalone Service Registry
You can run ServiceRegistry as a separate process and let services register themselves remotely.
Reference implementation:
examples/standalone_registry/registry_server.phpexamples/standalone_registry/HttpDiscoveryClient.phpexamples/standalone_registry/service_example.phpexamples/standalone_registry/gateway_example.php
Flow:
- Start registry process:
cd examples/standalone_registry
REGISTRY_HOST=0.0.0.0 REGISTRY_PORT=9090 php registry_server.php
- Start services (self-registration + heartbeat):
REGISTRY_URL=http://127.0.0.1:9090 SERVICE_NAME=user-service SERVICE_PORT=9101 SERVICE_URL=http://127.0.0.1:9101 SERVICE_ROUTE=/api/users INSTANCE_ID=user-1 php service_example.php
REGISTRY_URL=http://127.0.0.1:9090 SERVICE_NAME=order-service SERVICE_PORT=9102 SERVICE_URL=http://127.0.0.1:9102 SERVICE_ROUTE=/api/orders INSTANCE_ID=order-1 php service_example.php
- Start gateway that consumes registry:
REGISTRY_URL=http://127.0.0.1:9090 GATEWAY_PORT=9008 php gateway_example.php
- Call gateway routes:
curl -i http://127.0.0.1:9008/api/users curl -i http://127.0.0.1:9008/api/orders
Website Backend Example (4 Services)
For a complete content backend with separate services (docs, blog, community, auth) routed through gateway:
cd examples/website_backend
./start.sh
./smoke_test.sh
Gateway entrypoint: http://127.0.0.1:9008
Stop all services:
./stop.sh
Health and Resolution Rules
register()stores instance with statusUPand heartbeat timestamp set to now.resolve(name)picks only instances that are:- status
UP - fresh (
now - lastHeartbeat <= heartbeatTimeout)
- status
- If no healthy+fresh instance exists,
resolve()returnsnull. - Selection between healthy instances is round-robin.
Status Values
Allowed values for setStatus():
UPDOWNOUT_OF_SERVICEUNKNOWN
Invalid status throws exception.
Public API
Kislay\Discovery\ServiceRegistry methods:
__construct()setClient(Kislay\Discovery\ClientInterface $client): boolregister(string $name, string $url, ?array $metadata = null, ?string $instanceId = null): boolderegister(string $name, ?string $instanceId = null): boollist(): arrayresolve(string $name): ?stringlistInstances(string $name): arrayheartbeat(string $name, ?string $instanceId = null): boolsetStatus(string $name, string $status, ?string $instanceId = null): boolsetHeartbeatTimeout(int $milliseconds): boolsetBus(object $bus): bool
Kislay\Discovery\ClientInterface methods:
register(string $name, string $url): boolderegister(string $name): boolresolve(string $name): ?stringlist(): array
Optional richer client methods (auto-used by ServiceRegistry when present):
registerInstance(string $name, string $url, array $metadata = [], ?string $instanceId = null): boolderegisterInstance(string $name, ?string $instanceId = null): boollistInstances(string $name): arrayheartbeat(string $name, ?string $instanceId = null): boolsetStatus(string $name, string $status, ?string $instanceId = null): bool
Heartbeat Timeout Configuration
Default timeout is from env var KISLAY_DISCOVERY_HEARTBEAT_TIMEOUT_MS (default 90000).
Lower bound:
- values below
1000ms are clamped to1000ms with warning.
Optional RPC Mode
If extension is built with RPC support, remote discovery calls can be enabled with:
KISLAY_RPC_ENABLED=1KISLAY_RPC_DISCOVERY_ENDPOINT(default127.0.0.1:9090)KISLAY_RPC_TIMEOUT_MS(default200)
Event Bus Hooks
If setBus($bus) is configured, registry calls $bus->emit() for:
discovery.registerdiscovery.deregister
Payload shape:
nameurl
Test
cd kislayphp_discovery make test