priekÅ”vÄrds
Mana vietne, kuru vadÄ«ju kÄ hobiju, ir paredzÄta interesantu mÄjas lapu un personÄ«go vietÅu mitinÄÅ”anai. Å Ä« tÄma mani sÄka interesÄt jau paÅ”Ä programmÄÅ”anas ceļojuma sÄkumÄ, tajÄ brÄ«dÄ« mani aizrÄva izcilu profesionÄļu atraÅ”ana, kas raksta par sevi, saviem hobijiem un projektiem. Ieradums tos atklÄt sev saglabÄjies lÄ«dz mÅ«sdienÄm: gandrÄ«z katrÄ komerciÄlajÄ un ne pÄrÄk komerciÄlajÄ vietnÄ es turpinu skatÄ«ties kÄjenÄ, meklÄjot saites uz autoriem.
Idejas īstenoŔana
PirmÄ versija bija tikai html lapa manÄ personÄ«gajÄ vietnÄ, kur es ievietoju saites ar parakstiem ul sarakstÄ. IerakstÄ«jis 20 lappuses laika periodÄ, es sÄku domÄt, ka tas nav pÄrÄk efektÄ«vi, un nolÄmu mÄÄ£inÄt automatizÄt procesu. Izmantojot stackoverflow, es pamanÄ«ju, ka daudzi cilvÄki savos profilos norÄda vietnes, tÄpÄc es uzrakstÄ«ju parsÄtÄju php, kas vienkÄrÅ”i izgÄja cauri profiliem, sÄkot ar pirmo (adreses SO lÄ«dz Å”ai dienai ir Å”Ädas: `/users/1` ), izvilka saites no vÄlamÄ taga un pievienoja to SQLite.
To var saukt par otro versiju: āādesmitiem tÅ«kstoÅ”u URL kolekcija SQLite tabulÄ, kas aizstÄja statisko sarakstu html. Es veicu vienkÄrÅ”u meklÄÅ”anu Å”ajÄ sarakstÄ. Jo bija tikai URL, tad meklÄÅ”ana tika vienkÄrÅ”i balstÄ«ta uz tiem.
Å ajÄ posmÄ es pametu projektu un pÄc ilgÄka laika atgriezos pie tÄ. Å ajÄ posmÄ mans darba stÄžs jau bija vairÄk nekÄ trÄ«s gadi un es jutu, ka varu darÄ«t ko nopietnÄku. TurklÄt bija liela vÄlme apgÅ«t salÄ«dzinoÅ”i jaunas tehnoloÄ£ijas.
ModernÄ versija
problÄma
Jaunas vietnes pievieno konsoles komanda, kas sinhroni veic Å”Ädas darbÄ«bas:
- LejupielÄdÄ saturu pÄc URL
- Iestata karodziÅu, kas norÄda, vai HTTPS bija pieejams
- SaglabÄ vietnes bÅ«tÄ«bu
- Avota HTML un galvenes tiek saglabÄtas āindeksÄÅ”anasā vÄsturÄ
- ParsÄ saturu, izraksta nosaukumu un aprakstu
- SaglabÄ datus atseviÅ”Ä·Ä kolekcijÄ
Ar to pietika, lai vienkÄrÅ”i saglabÄtu vietnes un parÄdÄ«tu tÄs sarakstÄ:
TaÄu ideja par automÄtisku visu indeksÄÅ”anu, kategorizÄÅ”anu un ranžÄÅ”anu, visu atjauninÄÅ”anu Å”ajÄ paradigmÄ neiederÄjÄs. Pat vienkÄrÅ”i pievienojot tÄ«mekļa metodi lapu pievienoÅ”anai, bija nepiecieÅ”ama koda dublÄÅ”ana un bloÄ·ÄÅ”ana, lai izvairÄ«tos no iespÄjamÄs DDoS.
KopumÄ, protams, visu var izdarÄ«t sinhroni, un tÄ«mekļa metodÄ jÅ«s varat vienkÄrÅ”i saglabÄt URL, lai zvÄrÄ«gais dÄmons veiktu visus uzdevumus URL no saraksta. TomÄr pat Å”eit vÄrds ārindaā liek domÄt par sevi. Un, ja ir ieviesta rinda, tad visus uzdevumus var sadalÄ«t un veikt vismaz asinhroni.
Å Ä·Ä«dums
Ieviesiet rindas un izveidojiet uz notikumiem balstÄ«tu sistÄmu visu uzdevumu apstrÄdei. Un es jau ilgu laiku esmu vÄlÄjies izmÄÄ£inÄt Redis Streams.
Redis straumju izmantoŔana PHP
Jo TÄ kÄ mans ietvars nav viens no trim milžiem Symfony, Laravel, Yii, es vÄlÄtos atrast neatkarÄ«gu bibliotÄku. Bet, kÄ izrÄdÄ«jÄs (pirmajÄ pÄrbaudÄ), nav iespÄjams atrast atseviŔķas nopietnas bibliotÄkas. Viss, kas saistÄ«ts ar rindÄm, ir vai nu projekts no 3 saistÄ«bÄm pirms pieciem gadiem, vai arÄ« ir saistÄ«ts ar ietvaru.
Esmu daudz dzirdÄjis par Symfony kÄ atseviŔķu noderÄ«gu komponentu piegÄdÄtÄju, un dažus no tiem jau izmantoju. Un arÄ« dažas lietas no Laravel var izmantot, piemÄram, to ORM, bez paÅ”a ietvara klÄtbÅ«tnes.
simfonija/ziÅnesis
Pirmais kandidÄts uzreiz Ŕķita ideÄls un bez Å”aubÄm to uzstÄdÄ«ju. TaÄu google izmantoÅ”anas piemÄrus Ärpus Symfony izrÄdÄ«jÄs grÅ«tÄk. KÄ salikt autobusu ziÅojumu pÄrsÅ«tÄ«Å”anai no daudzÄm klasÄm ar universÄliem, bezjÄdzÄ«giem nosaukumiem un pat uz Redis?
DokumentÄcija oficiÄlajÄ vietnÄ bija diezgan detalizÄta, taÄu inicializÄcija tika aprakstÄ«ta tikai Symfony, izmantojot viÅu iecienÄ«tÄko YML un citas burvju metodes, kas nav paredzÄtas simfonistam. Man nebija nekÄdas intereses par paÅ”u instalÄÅ”anas procesu, it Ä«paÅ”i Jaungada brÄ«vdienÄs. Bet man tas bija jÄdara negaidÄ«ti ilgu laiku.
MÄÄ£inÄjums izdomÄt, kÄ izveidot sistÄmu, izmantojot Symfony avotus, arÄ« nav pats triviÄlais uzdevums saspringtÄ termiÅÄ:
Iedziļinoties Å”ajÄ visÄ un mÄÄ£inot kaut ko izdarÄ«t ar savÄm rokÄm, es nonÄcu pie secinÄjuma, ka es nodarbojos ar kaut kÄdiem kruÄ·iem un nolÄmu izmÄÄ£inÄt kaut ko citu.
izgaismots/rindÄ
IzrÄdÄ«jÄs, ka Ŕī bibliotÄka bija cieÅ”i saistÄ«ta ar Laravel infrastruktÅ«ru un daudzÄm citÄm atkarÄ«bÄm, tÄpÄc es tai netÄrÄju daudz laika: es to instalÄju, apskatÄ«ju, ieraudzÄ«ju atkarÄ«bas un izdzÄsu.
yiisoft/yii2-rinda
Nu, Å”eit tas uzreiz tika pieÅemts no nosaukuma, atkal, stingra saikne ar Yii2. Man bija jÄizmanto Ŕī bibliotÄka, un tÄ nebija slikta, taÄu es nedomÄju par to, ka tÄ ir pilnÄ«bÄ atkarÄ«ga no Yii2.
PÄrÄjie
Viss pÄrÄjais, ko atradu vietnÄ GitHub, bija neuzticami, novecojuÅ”i un pamesti projekti bez zvaigznÄm, dakÅ”Äm un daudzÄm saistÄ«bÄm.
Atgriezties uz symfony/messenger, tehniskÄ informÄcija
Man bija jÄizdomÄ Å”Ä« bibliotÄka, un, pavadot vairÄk laika, es to varÄju. IzrÄdÄ«jÄs, ka viss bija diezgan kodolÄ«gi un vienkÄrÅ”i. Lai iemūžinÄtu autobusu, es uztaisÄ«ju nelielu rÅ«pnÄ«cu, jo... Man vajadzÄja bÅ«t vairÄkÄm riepÄm un ar dažÄdiem hendleriem.
Tikai dažas darbības:
- MÄs izveidojam ziÅojumu apstrÄdÄtÄjus, kuriem vajadzÄtu bÅ«t vienkÄrÅ”i izsaucamiem
- MÄs tos iesaiÅojam programmÄ HandlerDescriptor (klase no bibliotÄkas)
- MÄs iesaiÅojam Å”os ādeskriptorusā HandlersLocator instancÄ
- HandlersLocator pievienoŔana MessageBus instancei
- MÄs nododam `SenderInterface` kopu pakalpojumam SendersLocator, manÄ gadÄ«jumÄ RedisTransport klaÅ”u gadÄ«jumiem, kas ir konfigurÄti acÄ«mredzamÄ veidÄ.
- SendersLocator pievienoŔana MessageBus instancei
MessageBus ir metode "->dispatch()", kas rÄ«kÄ HandlersLocator meklÄ atbilstoÅ”os apdarinÄtÄjus un nosÅ«ta tiem ziÅojumu, izmantojot atbilstoÅ”o "SenderInterface", lai nosÅ«tÄ«tu, izmantojot kopni (Redis straumes).
Konteinera konfigurÄcijÄ (Å”ajÄ gadÄ«jumÄ php-di) visu Å”o komplektu var konfigurÄt Å”Ädi:
CONTAINER_REDIS_TRANSPORT_SECRET => function (ContainerInterface $c) {
return new RedisTransport(
$c->get(CONTAINER_REDIS_STREAM_CONNECTION_SECRET),
$c->get(CONTAINER_SERIALIZER))
;
},
CONTAINER_REDIS_TRANSPORT_LOG => function (ContainerInterface $c) {
return new RedisTransport(
$c->get(CONTAINER_REDIS_STREAM_CONNECTION_LOG),
$c->get(CONTAINER_SERIALIZER))
;
},
CONTAINER_REDIS_STREAM_RECEIVER_SECRET => function (ContainerInterface $c) {
return new RedisReceiver(
$c->get(CONTAINER_REDIS_STREAM_CONNECTION_SECRET),
$c->get(CONTAINER_SERIALIZER)
);
},
CONTAINER_REDIS_STREAM_RECEIVER_LOG => function (ContainerInterface $c) {
return new RedisReceiver(
$c->get(CONTAINER_REDIS_STREAM_CONNECTION_LOG),
$c->get(CONTAINER_SERIALIZER)
);
},
CONTAINER_REDIS_STREAM_BUS => function (ContainerInterface $c) {
$sendersLocator = new SendersLocator([
AppMessagesSecretJsonMessages::class => [CONTAINER_REDIS_TRANSPORT_SECRET],
AppMessagesDaemonLogMessage::class => [CONTAINER_REDIS_TRANSPORT_LOG],
], $c);
$middleware[] = new SendMessageMiddleware($sendersLocator);
return new MessageBus($middleware);
},
CONTAINER_REDIS_STREAM_CONNECTION_SECRET => function (ContainerInterface $c) {
$host = 'bu-02-redis';
$port = 6379;
$dsn = "redis://$host:$port";
$options = [
'stream' => 'secret',
'group' => 'default',
'consumer' => 'default',
];
return Connection::fromDsn($dsn, $options);
},
CONTAINER_REDIS_STREAM_CONNECTION_LOG => function (ContainerInterface $c) {
$host = 'bu-02-redis';
$port = 6379;
$dsn = "redis://$host:$port";
$options = [
'stream' => 'log',
'group' => 'default',
'consumer' => 'default',
];
return Connection::fromDsn($dsn, $options);
},
Å eit var redzÄt, ka programmÄ SendersLocator esam pieŔķīruÅ”i dažÄdus ātransportusā diviem dažÄdiem ziÅojumiem, kuriem katram ir savs savienojums ar attiecÄ«gajÄm straumÄm.
Es izveidoju atseviŔķu demonstrÄcijas projektu, kas demonstrÄ trÄ«s dÄmonu lietojumprogrammu, kas sazinÄs savÄ starpÄ, izmantojot Å”Ädu kopni:
Bet es jums parÄdÄ«Å”u, kÄ patÄrÄtÄju var strukturÄt:
use AppMessagesDaemonLogMessage;
use SymfonyComponentMessengerHandlerHandlerDescriptor;
use SymfonyComponentMessengerHandlerHandlersLocator;
use SymfonyComponentMessengerMessageBus;
use SymfonyComponentMessengerMiddlewareHandleMessageMiddleware;
use SymfonyComponentMessengerMiddlewareSendMessageMiddleware;
use SymfonyComponentMessengerTransportSenderSendersLocator;
require_once __DIR__ . '/../vendor/autoload.php';
/** @var PsrContainerContainerInterface $container */
$container = require_once('config/container.php');
$handlers = [
DaemonLogMessage::class => [
new HandlerDescriptor(
function (DaemonLogMessage $m) {
error_log('DaemonLogHandler: message handled: / ' . $m->getMessage());
},
['from_transport' => CONTAINER_REDIS_TRANSPORT_LOG]
)
],
];
$middleware = [];
$middleware[] = new HandleMessageMiddleware(new HandlersLocator($handlers));
$sendersLocator = new SendersLocator(['*' => [CONTAINER_REDIS_TRANSPORT_LOG]], $container);
$middleware[] = new SendMessageMiddleware($sendersLocator);
$bus = new MessageBus($middleware);
$receivers = [
CONTAINER_REDIS_TRANSPORT_LOG => $container->get(CONTAINER_REDIS_STREAM_RECEIVER_LOG),
];
$w = new SymfonyComponentMessengerWorker($receivers, $bus, $container->get(CONTAINER_EVENT_DISPATCHER));
$w->run();
Å Ä«s infrastruktÅ«ras izmantoÅ”ana lietojumprogrammÄ
Ieviesot kopni savÄ aizmugurprogrammÄ, es atdalÄ«ju atseviŔķus posmus no vecÄs sinhronÄs komandas un izveidoju atseviŔķus apstrÄdÄtÄjus, no kuriem katrs dara savu.
Cauruļvads jaunas vietnes pievienoÅ”anai datu bÄzei izskatÄ«jÄs Å”Ädi:
Un uzreiz pÄc tam man kļuva daudz vieglÄk pievienot jaunu funkcionalitÄti, piemÄram, Rss izvilkÅ”anu un parsÄÅ”anu. Jo Å”im procesam ir nepiecieÅ”ams arÄ« oriÄ£inÄlais saturs, tad RSS saiÅ”u izvilkÅ”anas apdarinÄtÄjs, piemÄram, WebsiteIndexHistoryPersistor, abonÄ ziÅojumu āContent/HtmlContentā, apstrÄdÄ to un tÄlÄk nosÅ«ta vajadzÄ«go ziÅojumu pa savu konveijeru.
Galu galÄ mÄs nonÄcÄm pie vairÄkiem dÄmoniem, no kuriem katrs uztur savienojumus tikai ar nepiecieÅ”amajiem resursiem. PiemÄram, dÄmons rÄpulÄ«Å”i satur visus apdarinÄtÄjus, kuriem nepiecieÅ”ams pÄriet uz internetu, lai iegÅ«tu saturu, un dÄmonu noturÄties satur savienojumu ar datu bÄzi.
Tagad, tÄ vietÄ, lai veiktu atlasi no datu bÄzes, nepiecieÅ”amie ID pÄc to ievietoÅ”anas tiek vienkÄrÅ”i pÄrsÅ«tÄ«ti pa kopni visiem ieinteresÄtajiem apstrÄdÄtÄjiem.
Avots: www.habr.com