Переход к асинхронности
Переход к асинхронности
Вовремяпроверкиформынаналичиеспамамогутвозникнутьпроблемы。Вслучае,еслиответотAkismet APIбудетдолгим,нашастраницасформойтакжестанетработатьмедленнее。Худшийсценарий——мыможемсовсемпотерятькомментариииз——задостижениятайма,утаилинедоступностиAkismet API。
Видеаленамнужнонемедленновозвращатьответнаотправленнуюформу、априложениедолжносохранятьданныебезпопыткиихсразужеопубликовать。Проверить на спам можно и позже。
Установка статусов комментариев
Реализуем статусы (状态
) дл комментариев:提交
(отправлен),垃圾邮件
(спами)发表
(опубликован)。
Добавимсвойство状态
вкласс评论
:
1
$ob娱乐下载symfony控制台make:实体注释
Убедимся,“т то дл с о о ств”状态
по о мол л а ани и задан стат с с с с с с с с с с с с с с с提交
.
12 3 4 5 6 7 8 9 10 11 12 13
——/ src /实体/ Comment.php+ + + b / src /实体/ Comment.php@@ -38,8 +38,8 @@ class Comment #[ORM\Column(type: 'string',长度:255,nullable: true)] private $photoFilename;- #[ORM\Column(type: 'string',长度:255)]- private $state;+ #[ORM\列(类型:'string',长度:255,选项:["default" => "submitted"])]+ private $state = '已提交';公共函数__toString():字符串{
Создайте ми и и и и и и и а ан и и и
1
$ob娱乐下载Symfony控制台make:迁移
Изменитемиграцию,чтобывсесуществующиекомментариибылипоумолчаниюсостатусом发表
:
1 2 3 4 5 6 7 8 9 10
——/迁移/ Version00000000000000.php+ + + b /迁移/ Version00000000000000.php@@ -21,6 +21,7 @@ final class Version00000000000000 extends AbstractMigration {// this up()迁移是自动生成的,请根据您的需要修改$this->addSql('ALTER TABLE comment ADD state VARCHAR(255) DEFAULT \'submitted\' NOT NULL');+ $this->addSql("UPDATE comment SET state='published'");}公共函数关闭(Schema $ Schema):无效
Выполните ми и и и и и и и а ан и и и
1
$ob娱乐下载Symfony控制台原则:迁移:迁移
Обновителогикуотображения,чтобынастраницепоказывалисьтолькоопубликованныекомментарии:
12 3 4 5 6 7 8 9 10 11 12
——/ src /仓库/ CommentRepository.php+ + + b / src /仓库/ CommentRepository.php@@ -27,7 +27,9 @@ class CommentRepository extends ServiceEntityRepository {$query = $this->createQueryBuilder('c') ->andWhere('c. 1 ')Conference =: Conference ')+ - >引入(c。State =: State ')- > setParameter(“会议”,会议美元)+ ->setParameter('state', 'published')- > orderBy (c。->setMaxResults(self::PAGINATOR_PER_PAGE) ->setFirstResult($offset)
ОбновитеконфигурациюEasyAdmin,чтобыотображатьстатускомментариявадминистративнойпанели:
1 2 3 4 5 6 7 8 9 10
——/ src /控制器/ Admin / CommentCrudController.php+ + + b / src /控制器/ Admin / CommentCrudController.php@@类CommentCrudController extends AbstractCrudController ->setLabel('照片')->onlyOnIndex();+ yield TextField::new('state');$createdAt = DateTimeField::new('createdAt')->setFormTypeOptions(['html5' => true,
Незабудьтетакжеобновитьтесты,установивновоесвойство状态
вфикстурах:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
——/ src / DataFixtures / AppFixtures.php+ + + b / src / DataFixtures / AppFixtures.php@@ -37,8 +37,16 @@类AppFixtures扩展Fixture $comment1->setAuthor('Fabien');comment1 - > setEmail (fabien@example.com);$comment1->setText('This was a great conference.');+ $ comment1 - >设置状态(“发表”);经理- >保存($ comment1);+ $comment2 = new Comment();+ $ comment2 - > setConference阿姆斯特丹($);+ $ comment2 - > setAuthor(卢卡斯);+ $ comment2 - > setEmail (lucas@example.com);+ $comment2->setText('我认为这个将被缓和。');+ $经理- >保存($ comment2);+$admin = new admin ();管理- > setRoles ([' ROLE_ADMIN ']);管理- > setUsername(管理);
Длятестированияконтроллерасмоделируйтепроверкукомментария:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
——/ /控制器/ ConferenceControllerTest.php测试+ + + b /测试/控制器/ ConferenceControllerTest.php@@ -2,6 +2,8 @@名称空间应用\ \测试控制器;+使用App \ Repository \ CommentRepository;+使用原则\ ORM \ EntityManagerInterface;使用Syob娱乐下载mfony \包\ FrameworkBundle \ \ WebTestCase测试;class ConferenceControllerTest extends WebTestCase $client->submitForm('Submit', ['comment_form[author]' => 'Fabien', 'comment_form[text]' => '自动功能测试的一些反馈',- 'comment_form[email]' => 'me@automat.ed',+ 'comment_form[email]' => $email = 'me@automat.ed','comment_form[photo]' => dirname(__DIR__, 2).'/public/images/under-construction.gif',]);$ this - > assertResponseRedirects ();++ //模拟注释验证+ $comment = self::getContainer()->get(CommentRepository::class)->findOneByEmail($email);+ $评论- >设置状态(“发表”);+ self:: getContainer () - > (EntityManagerInterface::类)——>冲洗();+客户端- > followRedirect ();$this->assertSelectorExists('div:contains("有2个注释")');}
ВтестеPHPUnit)выможетеполучитьлюбойсервисизконтейнераспомощьюметодаself:: getContainer () - > get ()
,которыйтакжедаётдоступкнепубличнымсервисам。
Внедрение компонента
信使КомпонентуправляетасинхроннымкодомвSymfony:ob娱乐下载
1
$ob娱乐下载交响乐作曲家要求教义使者
Для о полнени асинхронных задач, от а а а тсообщениенаину обмена сообщениями.Шина сохраняет сообщение вочередьинемедленновозвращаетответ,чтобыисключитьлюбыезадержкиввашихприложениях。
Получательработаетпостоянновфоновомрежиме,читаяновыесообщенияизочередиивыполняясоответствующиезадачи。Получательможетработатькакнатомжесервере,гденаходитсясамоприложени,етакинаотдельномсервере。
ЭтонапоминаетобработкуHTTP -запросов,заисключениемтого,чтоздесьнетответов。
Создание об а абот и ика сообщений
Сообщени——эетокласссданными,вкоторомнедолжнобытьникакойлогики。Онбудетсериализовандляхранениявочереди,поэтомудержитевнемтолько”просты”есериализуемыеданные。
СоздайтеклассCommentMessage
:
Вмирен使者етконтроллеров,естьтолькообработчикисообщений。
СоздайтеклассCommentMessageHandler
в но о о ом прост а анст и им м应用MessageHandler \
, кот (оо т) р о нает, как (об а а ат) о а ат сообщенияCommentMessage
:
MessageHandlerInterface
——этомаркирующийинтерфейс。ЕгоналичиепомогаетSymob娱乐下载fonyпонять,чтокласснужноавтоматическизарегистрироватьинастроитьвкачествеобработчика信使。Посоглашениюлогикаобработчиканаходитсявметоде__invoke ()
.Подсказка об ис спол р емом типCommentMessage
дляединственногоаргументаэтогометодасообщает信使,какойклассонбудетобрабатывать。
Обновитеконтроллер,чтобыиспользоватьновуюсистему:
12 34 56 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
——/ src /控制器/ ConferenceController.php+ + + b / src /控制器/ ConferenceController.php@@ -5,14 +5,15 @@命名空间应用\控制器;使用App \实体\评论;使用App \实体\会议;使用App \ \ CommentFormType形式;+使用App \ \ CommentMessage消息;使用App \ Repository \ CommentRepository;使用App \ Repository \ ConferenceRepository;用程序\ SpamChecker;使用原则\ ORM \ EntityManagerInterface;控制器使ob娱乐下载用Symfony \包\ FrameworkBundle \ \ AbstractController;组件使用ob娱乐下载Symfony \ \ HttpFoundation \文件\ \ FileException异常;使用Syob娱乐下载mfony \ HttpFoundation \ \组件请求;组件使用ob娱乐下载Symfony \ \ HttpFoundation \反应;+使用Syob娱乐下载mfony \组件\ \ MessageBusInterface使者;使用Syob娱乐下载mfony \组件\路由\注释\路线;用树枝\环境;@@ -20,11 +21,13 @@类ConferenceController扩展AbstractController {private $twig;私人entityManager美元;+私人$bus;-公共函数__construct(Environment $twig, EntityManagerInterface $entityManager)+公共函数__construct(环境$twig, EntityManagerInterface $entityManager, MessageBusInterface $bus){$this->twig = $twig;$this->entityManager = $entityManager;+ $this->总线= $总线;} #[路由('/',名称:'首页')]@@ -36,7 +39,7 @@ class ConferenceController extends AbstractController} #[路由('/conference/{slug}',名称:'conference')]-公共功能显示(请求$请求,会议$会议,CommentRepository $ CommentRepository, SpamChecker $ SpamChecker,字符串$photoDir):响应+公共功能显示(请求$请求,会议$会议,CommentRepository $ CommentRepository,字符串$photoDir):响应{$comment = new comment ();$form = $this->createForm(CommentFormType::class, $comment);@@ -54,6 +57,7 @@ class ConferenceController extends AbstractController} $this->entityManager->persist($comment);+ $ this - > entityManager - >冲洗();$context = ['user_ip' => $request->getClientIp(), @@ -61,11 +65,8 @@ class ConferenceController extends AbstractController 'referrer' => $request->headers->get('referer'), 'permalink' => $request->getUri(),];- if (2 === $spamChecker->getSpamScore($comment, $context)) {- throw new \RuntimeException('公然的垃圾邮件,走开!');- - - - - -}- $ this - > entityManager - >冲洗();+ $this->bus->dispatch(new CommentMessage($comment->getId(), $context));return $this->redirectToRoute('conference', ['slug' => $conference->getSlug()]);}
Теперьвместотого,чтобызависетьотскоростиработыантиспам——сервиса,мыотправляемсообщениенашину。Затемобработчикрешает,чтоделатьсэтимсообщением。
Произошлочто——тонеожиданно:емыотделилинашконтроллеротантиспам——сервисаиперенеслилогикувновыйкласс-обработчик。Это идеал ни а а а。Проверьте код - всё а аботает。Операциивсёещёвыполняютсясинхронно,нокод,вероятно,ужестал”лучше”。
Переходим к асинхронности по о-настоящему
По умол л а ани ро б абот т и ики о о о о и ики о з з з а а т тс синхронно。Дляасинхронноговызованеобходимоуказать,какуюочередьиспользоватьдлякаждогообработчикавконфигурационномфайле配置/包/ messenger.yaml
:
1 2 3 4 5 6 7 8
——/ config /包/ messenger.yaml+ + + b / config /包/ messenger.yaml@@ -21,4 +21,4 @@框架:Symfony\Cob娱乐下载omponent\Notifier\Message\SmsMessage: async#路由你的消息到传输# App\Message\YourMessage: async+ App\Message\CommentMessage: async
Шина нас строена н оо тс о лку сообщений типа应用\ \ CommentMessage消息
вочередь异步
,котораяуправляется学说(согласноDSN,значениювпеременнойокруженияMESSENGER_TRANSPORT_DSN
изфайла.env
).Прощеговоря,мыиспользуемPostgreSQLвкачествеочередидлянашихсообщений。
Настроим таблицы Настроим таблицы триггеры PostgreSQL:
1
$ob娱乐下载Symfony控制台make:迁移
И запус ст И м м И И И И И И а а И И И базы данн н:
1
$ob娱乐下载Symfony控制台原则:迁移:迁移
提示
ЗакулисамиSyob娱乐下载mfonyиспользуетвстроеннуювPostgreSQLпроизводительную,масштабируемуюитранзакционнуюсистемуподпискиpub / sub (听
/通知
).ПрочитайтеглавуоRabbitMQ,еслихотитезаменитьброкерсообщенийсPostgreSQLнаRabbitMQ。
Получениесообщений
Приотправкеновогокомментария,проверканаспамбольшенесработает。Чтобы убедит т с в т том, доба а т т вызов функ иerror_log ()
вметодgetSpamScore ()
.,чВиднотосообщениенаходитсявочередииждётобработки。
Каквыпонимаете,уSymfob娱乐下载onyестькомандадляполучениясообщений。Давайте по полним её се о с ас:
1
$ob娱乐下载Symfony控制台messenger:consume async -vv
Команданемедленнополучитсообщение,отправленноедлякомментария:
1 2 3 4 5 6 7 8 9 10 11
[OK]从传输“异步”中消费消息。//一旦通过messenger:stop-workers命令接收到停止信号,worker将自动退出。//使用CONTROL-C退出worker11:30:20 INFO [messenger]已接收消息App\ message \CommentMessage ["message" => App\ message \CommentMessage^{…},"class" => "App\ message \CommentMessage"] 11:30:20 INFO [http_client]请求:"POST https://80cea32be1f6.rest.akismet.com/1.1/comment-check" 11:30:20 INFO [http_client]响应:"200 https://80cea32be1f6.rest.akismet.com/1.1/comment-check" 11:30:20 INFO [messenger] Message App\Message\CommentMessage handling by App\MessageHandler\CommentMessageHandler::__invoke [" Message" => App\Message\CommentMessage^{…},"class" => "App\Message\CommentMessage","handler" => "App\MessageHandler\CommentMessageHandler::__invoke"] 11:30:20 INFO [messenger] App\Message\CommentMessage was handled successfully (acknowledgement to transport)。["message" => App\ message \CommentMessage^{…},"class" => "App\ message \CommentMessage"]
Вседействияполучателясообщенийпишутсявлог,иноэтижедействияможноувидетьвконсоливреальномвремени,есликкомандедобавитьфлагvv
.Вы даже сможете у и идет и вызов к Akismet API。
Для остан новки полу с ател, нажмитеCtrl + C
.
Запуск воркеров в фоно о ом режиме
Вместотого,чтобызапускатьполучателякаждыйразпослеотправкикомментарияитутжеегоостанавливать,хотелосьбы,чтобыонработалнепрерывно,иприэтомненужнобылобыоткрыватьслишкоммногоокониливкладоктерминала。
ob娱乐下载Symfony CLIможетуправлятьтакимифоновымикомандамииливоркерами,еслидобавитьфлаг(- d
) к команде运行
.
Запуститеполучателясообщенийещёраз,нотеперьужевфоновомрежиме:
1
$ob娱乐下载Symfony run -d——watch=config,src,templates,vendor Symfony控制台messenger:consume async -vv
При испол зовании па амет а——看
ob娱乐下载Symfonyперезапускаеткомандукаждыйразприизменениифайловойсистемывдиректориях配置/
,src /
,模板/
или供应商/
.
请注意
Не испол ол зу те флагvv
,иначеполучитедублирующиесообщениявлогахкоманды服务器:日志
(ло ни ро сол ни сообщения)。
Еслиполучательперестаётработатьпокакой——либопричине(недостаточнопамяти,багитд)。,онбудетперезапущенавтоматически。НоSob娱乐下载ymfony CLIнеперезапуститполучателявтомслучае,еслиполучательвыдаетошибкусразупослезапуска。
Логи можно п осмат т и ива ат через командob娱乐下载symfony服务器:日志
вместесостальнымилогами,приходящимиотPHP,веб——сервераиприложения:
1
$ob娱乐下载symfony服务器:日志
Команда服务器:状态
во ое еде ер о о ое воркеры дл текущего п о оекта:
1 2 3 4
$ob娱乐下载命令symfony控制台messenger:使用PID 15774 (watching config/, src/, templates/)来运行async。
Чтобыостановитьворкер,нужнолибоостановитьвеб——сервер,либопринудительнозавершитьпроцесспоегоPIDпослезапускакоманды服务器:状态
:
1
$杀了15774
Повторная об с а а оо отка сообщений в сл с а а а а а а а а а а оо оо ибки
AkismetЧто,еслибудетнедоступенвовремяполучениясообщения吗?Этонеотразитсянапользователях,оправляющихкомментари,иногрозитпотерейсообщения,икакследствие,отсутствиемпроверкинаспам。
Укомпонента信使естьмеханизмповторныхпопытоквслучаевозникновенияисключенийвовремяобработкисообщений:
Еслиприобработкесообщениявозникнетошибка,получательповторитпопыткуещё3раза,азатемостановится。Новместоудаленияполучательперенесётсообщениевпостоянноехранилище——очередь失败的
, котора а и ис спол р о е е д у у у табли и и у у а анн н。
Просматриватьсообщения,давшиесбойиповторитьпопыткуихобработкиможноспомощьюследующихкоманд:
1 2 3
$ob娱乐下载Symfony控制台信使:失败:显示$ob娱乐下载Symfony控制台messenger:failed:重试
Выполнение воркеров на Platform.sh
ЧтобыполучатьсообщенияотPostgreSQL,намнужнопостояннозапускатькоманду信使:消费
.ВPlatform.shдляэтойзадачиотведенаспециальнаяроль-воркер:
ПодобноSob娱乐下载ymfony CLI, Platform.shпозволяетуправлятьперезагрузкамиилогами。
Чтобыпосмотретьлогиворкера,воспользуйтеськомандойниже:
1
$ob娱乐下载Syob直播appmfony云:logs——worker=messages all