Service registration and discovery

In the microservices governance process, registration of services initiated to third-party clusters, such as consul / etcd, is often involved. This chapter uses the swoft-consul component in the Swoft framework to implement service registration and discovery.

Service registration

Regardless of the http / rpc / ws service, you only need to listen to the SwooleEvent::START event to register the started service to a third-party cluster.

Registration service

This chapter takes the startup http server registration service as an example:

 <?php declare(strict_types=1);

namespace App\Listener;

use Swoft\Bean\Annotation\Mapping\Inject;
use Swoft\Consul\Agent;
use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\Http\Server\HttpServer;
use Swoft\Log\Helper\CLog;
use Swoft\Server\Swoole\SwooleEvent;

/**
 * Class RegisterServiceListener
 *
 * @since 2.0
 *
 * @Listener(event=SwooleEvent::START)
 */
class RegisterServiceListener implements EventHandlerInterface
{
    /**
     * @Inject()
     *
     * @var Agent
     */
    private $agent;

    /**
     * @param EventInterface $event
     */
    public function handle(EventInterface $event): void
    {
        /* @var HttpServer $httpServer */
        $httpServer = $event->getTarget();

        $service = [
            'ID'                => 'swoft',
            'Name'              => 'swoft',
            'Tags'              => [
                'http'
            ],
            'Address'           => '127.0.0.1',
            'Port'              => $httpServer->getPort(),
            'Meta'              => [
                'version' => '1.0'
            ],
            'EnableTagOverride' => false,
            'Weights'           => [
                'Passing' => 10,
                'Warning' => 1
            ]
        ];

        // Register
        $this->agent->registerService($service);
        CLog::info('Swoft http register service success by consul!');
    }
} 

Detailed process:

  • The object obtained by $event->getTarget() the object that starts the service. For example, the http started is the Swoft\Http\Server\HttpServer object.
  • The target object can get all the information about the startup service including the configuration information.
  • Register service information to consul based on service configuration information and business conditions

Swoole\Coroutine\Scheduler must be used, otherwise the service cannot be registered, and swoole 4.4+ supports this feature.

Cancel service

The service starts the registration service. If the service is closed or exited, you need to cancel the service registration. At this time, you can listen to a SwooleEvent::SHUTDOWN event as well as the registration. In this chapter, the Http server service is taken as an example:

 <?php declare(strict_types=1);

namespace App\Listener;

use Swoft\Bean\Annotation\Mapping\Inject;
use Swoft\Consul\Agent;
use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\Http\Server\HttpServer;
use Swoft\Server\Swoole\SwooleEvent;

/**
 * Class DeregisterServiceListener
 *
 * @since 2.0
 *
 * @Listener(SwooleEvent::SHUTDOWN)
 */
class DeregisterServiceListener implements EventHandlerInterface
{
    /**
     * @Inject()
     *
     * @var Agent
     */
    private $agent;

    /**
     * @param EventInterface $event
     */
    public function handle(EventInterface $event): void
    {
        /* @var HttpServer $httpServer */
        $httpServer = $event->getTarget();

        $this->agent->deregisterService('swoft');
    }
}     

Detailed process:

  • The object obtained by $event->getTarget() the object that starts the service. For example, the http started is the Swoft\Http\Server\HttpServer object.
  • The target object can get all the information about the startup service including the configuration information.
  • Cancel the supported services according to the service configuration information and the actual situation of the business.

Swoole\Coroutine\Scheduler must be used, otherwise the service cannot be registered, and swoole 4.4+ supports this feature.

Service discovery

In this chapter, the Rpc client is used as an example to deliver a list of available services through a third-party cluster consul.

First define the service provider:

 <?php declare(strict_types=1);

namespace App\Common;

use ReflectionException;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Bean\Annotation\Mapping\Inject;
use Swoft\Bean\Exception\ContainerException;
use Swoft\Consul\Agent;
use Swoft\Consul\Exception\ClientException;
use Swoft\Consul\Exception\ServerException;
use Swoft\Rpc\Client\Client;
use Swoft\Rpc\Client\Contract\ProviderInterface;

/**
 * Class RpcProvider
 *
 * @since 2.0
 *        
 * @Bean()
 */
class RpcProvider implements ProviderInterface
{
    /**
     * @Inject()
     *
     * @var Agent
     */
    private $agent;

    /**
     * @param Client $client
     *
     * @return array
     * @throws ReflectionException
     * @throws ContainerException
     * @throws ClientException
     * @throws ServerException
     * @example
     * [
     *     'host:port',
     *     'host:port',
     *     'host:port',
     * ]
     */
    public function getList(Client $client): array
    {
        // Get health service from consul
        $services = $this->agent->services();

        $services = [

        ];

        return $services;
    }
} 

Detailed process:

  • Implement the Swoft\Rpc\Client\Contract\ProviderInterface interface
  • Get current RPC service information according to the $client parameter
  • According to the service information, query the available services in the third-party cluster (consul)
  • Return a specified format array
  • This class must be marked with a @Bean as a bean object

Db / redis also supports the discovery of available services in this way, but needs to implement its corresponding interface.

Now that we have the service provider, we will configure it to the corresponding RPC service:

app/bean.php

 return [
    'user'           => [
      'class'   => ServiceClient::class,
      'host'    => '127.0.0.1',
      'port'    => 18307,
      'setting' => [
          'timeout'         => 0.5,
          'connect_timeout' => 1.0,
          'write_timeout'   => 10.0,
          'read_timeout'    => 0.5,
      ],
      'packet'  => bean('rpcClientPacket'),
      'provider' => bean(RpcProvider::class)
    ],
    'user.pool'      => [
      'class'  => ServicePool::class,
      'client' => bean('user')
    ],  
]; 
  • Here in the user service, a service provider RpcProvider::class (bean name) is injected through the provider parameter.
/docs/2.x/en/ms/govern/register-discovery.html
progress-bar