
Сначала давайте разберемся, что такое бессерверная архитектура и когда она нужна.
Бессерверная архитектура позволяет выполнять фрагменты кода без мороки с инфраструктурой: в этом случае управлением веб-сервером, физическим оборудованием и администрированием занимается облачный провайдер, позволяя вам сосредоточиться исключительно на коде.
AWS Lambda обеспечивает высокую доступность, причем плата взимается только за фактически затрачиваемое время вычислений. Этот сервис может быть весьма полезен для таких задач, как запуск cron-заданий, отправка уведомлений в режиме реального времени, предоставление доступа к API, обработка каких-нибудь событий при выполнении различных операций и т.д. В сети можно найти массу примеров использования сервиса.
Наш сценарий использования
Предоставить доступ к API, созданному с помощью Symfony, который публикует сообщения в LinkedIn. Процесс разработки будет включать этапы от написания до развертывания кода.
Пишем код
В Symfony 5-й версии появился новый компонент под названием Notifier, который дает возможность отправлять уведомления через разные сервисы (Slack, Twitter, Twilio и др.).
В Symfony нет встроенной поддержки LinkedIn, поэтому несколько месяцев назад я создал поверх Notifier шлюз для публикации контента в этой социальной сети. Исходный код шлюза можно посмотреть по ссылке, его же мы будем использовать и в этой демонстрации.
Приступаем
$ symfony new --full aws-lambda-linkedin-notifier$ cd aws-lambda-linkedin-notifier$ composer require eniams/linkedin-notifier
Включаем шлюз (см. документацию)
<?php// config/bundles.phpreturn [// others bundles,Eniams\Notifier\LinkedIn\LinkedInNotifierBundle::class => ['all' => true]];// .envLINKEDIN_DSN=
Логика публикации контента
<?phpclass PostContentController{ /** * @Route("/contents", name="post_content", methods="POST") */ public function __invoke(NotifierInterface $notifier, Request $request) { if(null !== $message = (\json_decode($request->getContent(), true)['message'] ?? null)) { $notifier->send(new Notification($message, ['chat/linkedin'])); return new JsonResponse('message posted with success', 201); } throw new BadRequestException('Missing "message" in body'); }}
Логика проста: мы предоставляем доступ к API через маршрут
/contents
, который принимает запрос POST с сообщением
message
в его теле.
В 11-й строке мы отправляем публикуемое сообщение в LinkedIn благодаря Symfony и шлюзу это делается очень просто!
Будучи профессиональными разработчиками, покроем этот код автотестами:
<?phpclass PostContentControllerTest extends WebTestCase /** * @dataProvider methodProvider */ public function testANoPostRequestShouldReturnA405(string $method) { $client = static::createClient(); $client->request($method, '/contents'); self::assertEquals(405, $client->getResponse()->getStatusCode()); } public function testAPostRequestWithoutAMessageInBodyShouldReturnA400() { $client = static::createClient(); $client->request('POST', '/contents'); self::assertEquals(400, $client->getResponse()->getStatusCode()); } public function testAPostRequestWithAMessageInBodyShouldReturnA201() { $request = new Request([],[],[],[],[],[], json_encode(['message' => 'Hello World'])); $notifier = new class implements NotifierInterface { public function send(Notification $notification, Recipient ...$recipients): void { } }; $controller = new PostContentController(); $response = $controller->__invoke($notifier, $request); self::assertEquals(201, $response->getStatusCode()); } public function methodProvider() { return [ ['GET'], ['PUT'], ['DELETE'], ]; }view rawTestPostContentController.php hosted with by GitHub
Код готов! Пришло время его развернуть
Стоп! Что?! AWS Lambda не поддерживает PHP!
Именно так: AWS Lambda поддерживает не все языки программирования, а только некоторые, в том числе Go, Java, Python, Ruby, NodeJS и .NET.
Теперь надо учить новый язык и переписывать код? Надеюсь, нет!
Ничего переписывать не придется благодаря Матье Напполи (Matthieu Nappoli), создателю Bref.sh, и замечательной команде, помогающей ему поддерживать этот проект с открытым исходным кодом.
Bref позволяет развертывать PHP-приложения в AWS и запускать их на AWS Lambda.
Конфигурация развертывания
Добавим в kernel.php обработку логов:
<?php // Kernel.php public function getLogDir(): string { if (getenv('LAMBDA_TASK_ROOT') !== false) { return '/tmp/log/'; } return parent::getLogDir(); } public function getCacheDir() { if (getenv('LAMBDA_TASK_ROOT') !== false) { return '/tmp/cache/'.$this->environment; } return parent::getCacheDir(); }
Подготовим фреймворк Serverless (см. документацию):
$ npm install -g serverless$ serverless config credentials --provider aws --key --secret$ composer require bref/bref
Зададим конфигурацию в файле serverless.yaml:
service: notifier-linkedin-apiprovider: name: aws region: eu-west-3 runtime: provided environment: # env vars APP_ENV: prod LINKEDIN_DSN: YOUR_DSNplugins: - ./vendor/bref/breffunctions: website: handler: public/index.php # bootstrap layers: - ${bref:layer.php-73-fpm} # https://bref.sh/docs/runtimes/index.html#usage timeout: 28 # Timeout to stop the compute time events: - http: 'POST /contents' # Only POST to /contents are allowedpackage: exclude: - 'tests/**'view rawserverless.yaml hosted with by GitHub
Развертываем!
$ serverless deployServerless: Packaging service...Serverless: Excluding development dependencies...Serverless: Uploading CloudFormation file to S3...Serverless: Uploading artifacts...Serverless: Uploading service notifier-linkedin-api.zip file to S3 (10.05 MB)...Serverless: Validating template...Serverless: Updating Stack...Serverless: Checking Stack update progress.......................Serverless: Stack update finished...Service Informationservice: notifier-linkedin-apistage: devregion: eu-west-3stack: notifier-linkedin-api-devresources: 15api keys: Noneendpoints: POST - https://xxx.execute-api.eu-west-3.amazonaws.com/dev/contentsfunctions: website: notifier-linkedin-api-dev-websitelayers: NoneServerless: Removing old service artifacts from S3...Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
Теперь наш код развернут в AWS Lambda, а API доступен по адресу
https://xxx.execute-api.eu-west-3.amazonaws.com/dev/contents
.
Попробуем:


Перевод материала подготовлен в рамках курса "Symfony Framework". Если интересно узнать о курсе больше, приглашаем на день открытых дверей онлайн, где преподаватель расскажет о формате и программе обучения.