پی ایچ پی بیک اینڈ کو ریڈیس اسٹریمز بس میں منتقل کرنا اور فریم ورک سے آزاد لائبریری کا انتخاب کرنا

پی ایچ پی بیک اینڈ کو ریڈیس اسٹریمز بس میں منتقل کرنا اور فریم ورک سے آزاد لائبریری کا انتخاب کرنا

کردار

میری ویب سائٹ، جسے میں شوق کے طور پر چلاتا ہوں، دلچسپ ہوم پیجز اور ذاتی سائٹس کی میزبانی کے لیے ڈیزائن کیا گیا ہے۔ یہ موضوع میرے پروگرامنگ کے سفر کے آغاز میں ہی میری دلچسپی کا باعث بننا شروع ہوا؛ اس وقت میں اپنے بارے میں، اپنے مشاغل اور منصوبوں کے بارے میں لکھنے والے عظیم پیشہ ور افراد کو تلاش کر کے متوجہ ہوا۔ ان کو اپنے لیے دریافت کرنے کی عادت آج تک برقرار ہے: تقریباً ہر تجارتی اور بہت زیادہ تجارتی سائٹ پر، میں مصنفین کے لنکس کی تلاش میں فوٹر میں دیکھتا رہتا ہوں۔

خیال کا نفاذ

پہلا ورژن میری ذاتی ویب سائٹ پر صرف ایک HTML صفحہ تھا، جہاں میں نے دستخطوں کے ساتھ لنکس کو ul فہرست میں ڈال دیا تھا۔ وقت کے ساتھ ساتھ 20 صفحات ٹائپ کرنے کے بعد، میں نے سوچنا شروع کیا کہ یہ زیادہ موثر نہیں ہے اور میں نے اس عمل کو خودکار کرنے کی کوشش کرنے کا فیصلہ کیا۔ اسٹیک اوور فلو پر، میں نے دیکھا کہ بہت سے لوگ اپنے پروفائلز میں سائٹس کی نشاندہی کرتے ہیں، اس لیے میں نے php میں ایک پارسر لکھا، جو صرف پروفائلز سے گزرتا ہے، پہلے سے شروع ہوتا ہے (SO پر آج تک کے پتے اس طرح ہیں: `/users/1` ) نے مطلوبہ ٹیگ سے لنکس نکالے اور اسے SQLite میں شامل کیا۔

اسے دوسرا ورژن کہا جا سکتا ہے: SQLite ٹیبل میں دسیوں ہزار یو آر ایل کا مجموعہ، جس نے HTML میں جامد فہرست کی جگہ لے لی۔ میں نے اس فہرست پر ایک سادہ سی تلاش کی۔ کیونکہ وہاں صرف URLs تھے، پھر تلاش صرف ان پر مبنی تھی۔

اس مرحلے پر میں نے اس منصوبے کو ترک کر دیا اور ایک طویل عرصے کے بعد اس پر واپس آیا۔ اس مرحلے پر، میرا کام کا تجربہ پہلے ہی تین سال سے زیادہ کا تھا اور میں نے محسوس کیا کہ میں کچھ زیادہ سنجیدہ کر سکتا ہوں۔ اس کے علاوہ، نسبتاً نئی ٹیکنالوجی میں مہارت حاصل کرنے کی بڑی خواہش تھی۔

جدید ورژن

پروجیکٹ ڈوکر میں تعینات، ڈیٹا بیس کو منگو ڈی بی میں منتقل کر دیا گیا، اور حال ہی میں، مولی شامل کی گئی، جو پہلے صرف کیشنگ کے لیے تھی۔ پی ایچ پی مائیکرو فریم ورکس میں سے ایک کو بنیاد کے طور پر استعمال کیا جاتا ہے۔

مسئلہ

نئی سائٹیں کنسول کمانڈ کے ذریعہ شامل کی جاتی ہیں جو ہم وقت سازی سے درج ذیل کام کرتی ہیں۔

  • URL کے ذریعے مواد ڈاؤن لوڈ کرتا ہے۔
  • ایک جھنڈا سیٹ کرتا ہے جو یہ بتاتا ہے کہ آیا HTTPS دستیاب تھا۔
  • ویب سائٹ کے جوہر کو محفوظ رکھتا ہے۔
  • ماخذ HTML اور ہیڈر "اشاریہ سازی" کی تاریخ میں محفوظ کیے گئے ہیں۔
  • مواد کو پارس کرتا ہے، عنوان اور تفصیل نکالتا ہے۔
  • ڈیٹا کو ایک علیحدہ مجموعہ میں محفوظ کرتا ہے۔

یہ صرف سائٹس کو اسٹور کرنے اور انہیں فہرست میں ڈسپلے کرنے کے لیے کافی تھا:

پی ایچ پی بیک اینڈ کو ریڈیس اسٹریمز بس میں منتقل کرنا اور فریم ورک سے آزاد لائبریری کا انتخاب کرنا

لیکن ہر چیز کو خود بخود اشاریہ سازی، درجہ بندی اور درجہ بندی کرنے، ہر چیز کو تازہ ترین رکھنے کا خیال اس تمثیل میں بالکل فٹ نہیں آتا تھا۔ یہاں تک کہ صفحات کو شامل کرنے کے لیے صرف ایک ویب طریقہ شامل کرنا مطلوبہ کوڈ کی نقل اور ممکنہ DDoS سے بچنے کے لیے بلاک کرنا۔

عام طور پر، بلاشبہ، سب کچھ ہم آہنگی سے کیا جا سکتا ہے، اور ویب کے طریقہ کار میں آپ آسانی سے یو آر ایل کو محفوظ کر سکتے ہیں تاکہ شیطانی ڈیمون فہرست میں سے یو آر ایل کے لیے تمام کام انجام دے سکے۔ لیکن پھر بھی، یہاں تک کہ لفظ "قطار" خود تجویز کرتا ہے۔ اور اگر ایک قطار کو لاگو کیا جاتا ہے، تو تمام کاموں کو تقسیم کیا جا سکتا ہے اور کم از کم متضاد طور پر انجام دیا جا سکتا ہے.

حل

قطاروں کو لاگو کریں اور تمام کاموں پر کارروائی کرنے کے لیے ایونٹ پر مبنی نظام بنائیں۔ اور میں ایک طویل عرصے سے ریڈیس اسٹریمز کو آزمانا چاہتا ہوں۔

پی ایچ پی میں ریڈیس اسٹریمز کا استعمال

کیونکہ چونکہ میرا فریم ورک تین جنات Symfony, Laravel, Yii میں سے ایک نہیں ہے، اس لیے میں ایک آزاد لائبریری تلاش کرنا چاہوں گا۔ لیکن، جیسا کہ یہ نکلا (پہلے امتحان پر)، انفرادی سنجیدہ لائبریریوں کو تلاش کرنا ناممکن ہے۔ قطاروں سے متعلق ہر چیز یا تو پانچ سال پہلے کے 3 کمٹ کا ایک پروجیکٹ ہے، یا فریم ورک سے منسلک ہے۔

میں نے انفرادی مفید اجزاء کے سپلائر کے طور پر سیمفونی کے بارے میں بہت کچھ سنا ہے، اور میں پہلے ہی ان میں سے کچھ استعمال کرتا ہوں۔ اور Laravel سے کچھ چیزیں بھی استعمال کی جا سکتی ہیں، مثال کے طور پر ان کا ORM، خود فریم ورک کی موجودگی کے بغیر۔

سمفونی/میسنجر

پہلا امیدوار فوری طور پر مثالی لگ رہا تھا اور بغیر کسی شک کے میں نے اسے انسٹال کیا۔ لیکن سیمفونی کے باہر استعمال کی مثالوں کو گوگل کرنا زیادہ مشکل ثابت ہوا۔ آفاقی، بے معنی ناموں، پیغامات بھیجنے کے لیے بس، اور ریڈیس پر بھی کلاسوں کے ایک گروپ سے کیسے جمع ہوں؟

پی ایچ پی بیک اینڈ کو ریڈیس اسٹریمز بس میں منتقل کرنا اور فریم ورک سے آزاد لائبریری کا انتخاب کرنا

آفیشل سائٹ پر موجود دستاویزات کافی تفصیلی تھیں، لیکن ابتداء صرف سمفونی کے لیے ان کے پسندیدہ YML اور غیر سمفونیسٹ کے لیے دیگر جادوئی طریقوں کا استعمال کرتے ہوئے بیان کی گئی تھی۔ مجھے خود تنصیب کے عمل میں کوئی دلچسپی نہیں تھی، خاص طور پر نئے سال کی تعطیلات کے دوران۔ لیکن مجھے یہ کام غیر متوقع طور پر طویل عرصے تک کرنا پڑا۔

یہ جاننے کی کوشش کرنا کہ سیمفونی ذرائع کا استعمال کرتے ہوئے سسٹم کو کس طرح انسٹیٹیوٹ کرنا ہے ایک سخت ڈیڈ لائن کے لیے سب سے معمولی کام بھی نہیں ہے:

پی ایچ پی بیک اینڈ کو ریڈیس اسٹریمز بس میں منتقل کرنا اور فریم ورک سے آزاد لائبریری کا انتخاب کرنا

اس سب کو جاننے اور اپنے ہاتھوں سے کچھ کرنے کی کوشش کرنے کے بعد، میں اس نتیجے پر پہنچا کہ میں کسی قسم کی بیساکھیوں سے کام کر رہا ہوں اور کچھ اور کرنے کا فیصلہ کیا۔

روشن/قطار

پتہ چلا کہ یہ لائبریری Laravel انفراسٹرکچر اور دیگر انحصار کے ایک گروپ سے مضبوطی سے جڑی ہوئی تھی، اس لیے میں نے اس پر زیادہ وقت نہیں گزارا: میں نے اسے انسٹال کیا، اسے دیکھا، انحصار دیکھا اور اسے حذف کر دیا۔

yiisoft/yii2-queue

ٹھیک ہے، یہاں یہ فوری طور پر نام سے فرض کیا گیا تھا، ایک بار پھر، Yii2 سے سخت تعلق۔ مجھے اس لائبریری کو استعمال کرنا پڑا اور یہ برا نہیں تھا، لیکن میں نے اس حقیقت کے بارے میں نہیں سوچا کہ یہ مکمل طور پر Yii2 پر منحصر ہے۔

باقی

باقی سب کچھ جو میں نے GitHub پر پایا وہ ناقابل اعتبار، پرانے اور ستاروں، کانٹے اور بڑی تعداد میں کمٹ کے بغیر چھوڑے گئے منصوبے تھے۔

سمفونی/میسنجر، تکنیکی تفصیلات پر واپس جائیں۔

مجھے اس لائبریری کا پتہ لگانا پڑا اور، کچھ اور وقت گزارنے کے بعد، میں اس قابل ہو گیا۔ یہ پتہ چلا کہ سب کچھ بہت جامع اور سادہ تھا. بس شروع کرنے کے لیے، میں نے ایک چھوٹی سی فیکٹری بنائی، کیونکہ... میرے پاس کئی ٹائر اور مختلف ہینڈلرز کے ساتھ ہونا تھا۔

پی ایچ پی بیک اینڈ کو ریڈیس اسٹریمز بس میں منتقل کرنا اور فریم ورک سے آزاد لائبریری کا انتخاب کرنا

صرف چند قدم:

  • ہم میسج ہینڈلرز بناتے ہیں جو کہ صرف قابل کال ہونے چاہئیں
  • ہم انہیں HandlerDescriptor میں لپیٹتے ہیں (لائبریری سے کلاس)
  • ہم ان "ڈیسکریپٹرز" کو ہینڈلرز لوکیٹر مثال میں لپیٹتے ہیں۔
  • ہینڈلرز لوکیٹر کو میسج بس مثال میں شامل کرنا
  • ہم 'SenderInterface' کا ایک سیٹ SendersLocator کو دیتے ہیں، میرے معاملے میں 'RedisTransport' کلاسز کی مثالیں، جو واضح طریقے سے ترتیب دی گئی ہیں۔
  • MessageBus مثال میں SendersLocator کو شامل کرنا

MessageBus میں ایک `->dispatch()` طریقہ ہے جو HandlersLocator میں مناسب ہینڈلرز کو تلاش کرتا ہے اور بس (Redis streams) کے ذریعے بھیجنے کے لیے متعلقہ `SenderInterface` کا استعمال کرتے ہوئے انہیں پیغام پہنچاتا ہے۔

کنٹینر کنفیگریشن میں (اس معاملے میں php-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);
        },

یہاں آپ دیکھ سکتے ہیں کہ SendersLocator میں ہم نے دو مختلف پیغامات کے لیے مختلف "ٹرانسپورٹس" تفویض کیے ہیں، جن میں سے ہر ایک کا متعلقہ سلسلے سے اپنا تعلق ہے۔

میں نے ایک علیحدہ ڈیمو پروجیکٹ بنایا جس میں درج ذیل بس کا استعمال کرتے ہوئے ایک دوسرے کے ساتھ بات چیت کرنے والے تین ڈیمنز کی درخواست کا مظاہرہ کیا گیا: https://github.com/backend-university/products/tree/master/products/02-redis-streams-bus.

لیکن میں آپ کو دکھاؤں گا کہ صارف کو کس طرح تشکیل دیا جا سکتا ہے:

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();

ایک درخواست میں اس بنیادی ڈھانچے کو استعمال کرنا

اپنے بیک اینڈ میں بس کو لاگو کرنے کے بعد، میں نے پرانی سنکرونس کمانڈ سے انفرادی مراحل کو الگ کیا اور الگ الگ ہینڈلر بنائے، جن میں سے ہر ایک اپنا کام کرتا ہے۔

ڈیٹا بیس میں ایک نئی سائٹ شامل کرنے کی پائپ لائن اس طرح نظر آتی تھی:

پی ایچ پی بیک اینڈ کو ریڈیس اسٹریمز بس میں منتقل کرنا اور فریم ورک سے آزاد لائبریری کا انتخاب کرنا

اور اس کے فوراً بعد، میرے لیے نئی فعالیت شامل کرنا بہت آسان ہو گیا، مثلاً Rss کو نکالنا اور پارس کرنا۔ کیونکہ اس عمل کے لیے اصل مواد کی بھی ضرورت ہوتی ہے، پھر RSS لنک ایکسٹریکٹر ہینڈلر، جیسے WebsiteIndexHistoryPersistor، "Content/HtmlContent" پیغام کو سبسکرائب کرتا ہے، اس پر کارروائی کرتا ہے اور مطلوبہ پیغام کو اپنی پائپ لائن کے ساتھ آگے منتقل کرتا ہے۔

پی ایچ پی بیک اینڈ کو ریڈیس اسٹریمز بس میں منتقل کرنا اور فریم ورک سے آزاد لائبریری کا انتخاب کرنا

آخر میں، ہم نے کئی ڈیمن کے ساتھ ختم کیا، جن میں سے ہر ایک صرف ضروری وسائل سے کنکشن برقرار رکھتا ہے. مثال کے طور پر ایک شیطان crawlers تمام ہینڈلرز پر مشتمل ہے جو مواد کے لیے انٹرنیٹ پر جانے کی ضرورت ہے، اور ڈیمون اصرار ڈیٹا بیس سے کنکشن رکھتا ہے۔

اب، ڈیٹا بیس سے منتخب کرنے کے بجائے، پرسیسٹر کے ذریعے داخل کرنے کے بعد مطلوبہ آئی ڈیز کو بس کے ذریعے تمام دلچسپی رکھنے والے ہینڈلرز تک پہنچایا جاتا ہے۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں