butschster/lumen-microservice

此包将帮助您使用Lumen框架作为微服务,无需额外知识即可使用AMQP和JMS序列化器。

1.22.1 2021-01-21 13:06 UTC

This package is auto-updated.

Last update: 2024-09-20 22:12:58 UTC


README

Build Status Latest Stable Version Total Downloads License heading

此包可以帮助您使用Lumen框架或Laravel作为微服务,无需额外知识。只需安装包,创建交换点类,并通过MQ在服务之间交换信息即可。

此包使用 JMS\Serializer 进行消息序列化。

备注:您可以使用此服务进行测试 https://www.cloudamqp.com。他们有一个免费计划。

特性

  • 开箱即用,易于使用
  • 易于配置
  • jms serializer
  • 开箱即用MQ
  • 经过充分测试

要求

  • Lumen或Laravel 7.x至8.x
  • PHP 7.4及以上

安装和配置

从命令行运行

composer require butschster/lumen-microservice

注册服务提供者

// bootstrap.php
$app->register(Butschster\Exchanger\Providers\ExchangeServiceProvider::class);

将包的 config 目录中的配置文件复制到您的Lumen应用中并注册它们。

$app->configure('amqp');
$app->configure('microservice');
$app->configure('serializer');

向您的 .env 文件中添加变量

MICROSERVICE_NAME=...
MICROSERVICE_VERSION=1.0.0
RABBITMQ_HOST=...
RABBITMQ_USERNAME=...
RABBITMQ_PASSWORD=...
RABBITMQ_VHOST=...
JWT_SECRET=...

在您的应用中创建交换点

此点将用于接收来自其他服务的请求,并发送响应。

namespace App\Exchange\Point;

use Butschster\Exchanger\Contracts\Exchange\Point as PointContract;
use Psr\Log\LoggerInterface;
use Butschster\Exchanger\Contracts\Exchange\IncomingRequest;

class Point implements PointContract
{
    public function getName(): string
    {
        return 'com.test';
    }

    /**
     * @subject com.test.action.test
     */
    public function testSubject(IncomingRequest $request, LoggerInterface $logger)
    {
        $logger->info(
            sprintf('info [%s]:', $request->getSubject()),
            [$request->getBody()]
        );

        // Response
        $payload = new ...;
        $request->sendResponse($payload);

        // or
        $request->sendEmptyResponse();

        // or
        $request->acknowledge();
    }

    /**
     * @subject com.test.action.test1
     */
    public function anotherTestSubject(IncomingRequest $request, LoggerInterface $logger)
    {
        $payload = new ...;
        $request->sendResponse($payload);
    }
}

然后注册此点

use App\Exchange\Point;
use Illuminate\Support\ServiceProvider;
use Butschster\Exchanger\Contracts\Exchange\Point as PointContract;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(PointContract::class, Point::class);
    }
}

注册控制台命令

use Butschster\Exchanger\Console\Commands\RunMicroservice;

class Kernel extends ConsoleKernel
{
    protected $commands = [
        RunMicroservice::class
    ];
}

发送请求

要从其他服务请求信息,您应使用 ExchangeManager

use Butschster\Exchanger\Contracts\ExchangeManager;

class UserController {

    public function getUser(ExchangeManager $manager, int $userId)
    {
        $requestPayload = new GetUserByIdPayload($userId);

        $request = $manager->request('com.test.action.test', $requestPayload);
        $user = $request->send(UserPayload::class);

        // You can set delivery mode to persistent
        $user = $request->send(UserPayload::class, true);
    }
}

// User Request Payload

use JMS\Serializer\Annotation\Type;

class GetUserByIdPayload implements \Butschster\Exchanger\Contracts\Exchange\Payload
{
    /** @Type("string") */
    public string $userId;
    public function __construct(string $userId)
    {
        $this->userId = $userId;
    }
}

// User Payload

use JMS\Serializer\Annotation\Type;

class UserPayload implements \Butschster\Exchanger\Contracts\Exchange\Payload
{
    /** @Type("string") */
    public string $id;

    /** @Type("string") */
    public string $username;

    /** @Type("string") */
    public string $email;

    /** @Type("Carbon\Carbon") */
    public \Carbon\Carbon $createdAt;
}

广播

如果您想发送事件,应使用 ExchangeManagerbroadcast 方法

use Illuminate\Http\Request;
use Butschster\Exchanger\Contracts\ExchangeManager;

class UserController {

    public function update(ExchangeManager $manager, Request $request, User $user)
    {
        $payload = new UserPayload();
        $data = $request->validate(...);
        $user->update($data);

        $payload->id = $user->id;
        $payload->username = $user->username;
        ...
        
        $manager->broadcast('com.user.event.updated', $payload);

        // You can set delivery mode to persistent
        $manager->broadcast('com.user.event.updated', $payload, true);
    }
}

实体映射

您可以在 serializer.php 配置中配置实体映射。

// serializer.php
return [
    'mapping' => [
        Domain\User\Entities\User::class => [
            'to' => Payloads\User::class,
            'attributes' => [
                'id' => ['type' => 'string'],
                'username' => ['type' => 'string'],
                'email' => ['type' => 'string'],
                'balance' => ['type' => Domain\Billing\Money\Token::class],
                'createdAt' => ['type' => \Carbon\Carbon::class],
            ]
        ],
        Domain\Billing\Money\Token::class => [
            'to' => Payloads\Billing\Token::class,
            'attributes' => [
                'amount' => ['type' => \Brick\Math\BigDecimal::class],
            ]
        ],
    ],
    // ...
];

然后您可以轻松地将实体转换为有效载荷

use Butschster\Exchanger\Contracts\Serializer\ObjectsMapper;

class UserController {

    public function update(ObjectsMapper $mapper, ExchangeManager $manager, Request $request, Domain\User\Entities\User $user)
    {
        $data = $request->validate(...);
        $user->update($data);
        
        $payload = $mapper->toPayload($user);
        
        $manager->broadcast('com.user.event.updated', $payload);
    }
}

自定义类型

如果您想使用自定义JMS序列化器类型,应使用处理器。它们可以添加到 serializer.php 配置中。

// serializer.php
return [
    'handlers' => [
        Butschster\Exchanger\Jms\Handlers\CarbonHandler::class,
        Infrastructure\Microservice\Jms\Handlers\BigDecimalHandler::class
    ],
    // ..
];

// BigDecimalHandler.php

namespace Infrastructure\Microservice\Jms\Handlers;

use Brick\Math\BigDecimal;
use Butschster\Exchanger\Contracts\Serializer;
use Butschster\Exchanger\Contracts\Serializer\Handler;
use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\HandlerRegistryInterface;

class BigDecimalHandler implements Handler
{
    public function serialize(Serializer $serializer, HandlerRegistryInterface $registry): void
    {
        $registry->registerHandler(
            GraphNavigatorInterface::DIRECTION_SERIALIZATION,
            BigDecimal::class,
            'json',
            function ($visitor, BigDecimal $value, array $type) {
                return $value->toInt();
            }
        );
    }

    public function deserialize(Serializer $serializer, HandlerRegistryInterface $registry): void
    {
        $registry->registerHandler(
            GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
            BigDecimal::class,
            'json',
            function ($visitor, $value, array $type) {
                return BigDecimal::of($value);
            }
        );
    }
}

服务运行

此单条命令将运行您的微服务并开始监听在交换点中注册的命令。

php artisan service:run

Supervisor是Linux操作系统的进程监控器,如果horizon进程失败,则会自动重启。要在Ubuntu上安装Supervisor,您可以使用以下命令

sudo apt-get install supervisor

Supervisor配置文件通常存储在 /etc/supervisor/conf.d 目录中。在此目录中,您可以创建任意数量的配置文件,以指示supervisor如何监控您的进程。例如,让我们创建一个microservice.conf文件,该文件启动并监控一个进程

[program:microservice]
process_name=%(program_name)s
command=php /var/www/app.com/artisan service:run
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/www/app.com/storage/logs/microservice.log
stopwaitsecs=3600

一旦配置文件已创建,您可以使用以下命令更新Supervisor配置并启动进程

sudo supervisorctl reread

sudo supervisorctl update

sudo supervisorctl start microservice