रेडिस कतार

रेडिस पर आधारित संदेश कतार, संदेश में विलंबित प्रसंस्करण के समर्थन करता है।

स्थापना
composer require webman/redis-queue

विन्यास फ़ाइल
रेडिस विन्यास फ़ाइल स्वतः config/plugin/webman/redis-queue/redis.php में जनरेट होती है, निम्नलिखित समान है:

<?php
return [
    'default' => [
        'host' => 'redis://127.0.0.1:6379',
        'options' => [
            'auth' => '',         // पासवर्ड, वैकल्पिक पैरामीटर
            'db' => 0,            // डेटाबेस
            'max_attempts'  => 5, // सेवना विफलता के बाद, पुन:प्राप्ति की संख्या
            'retry_seconds' => 5, // पुन:प्राप्ति अंतराल, सेकंड में
        ]
    ],
];

सेवना विफलता पुन:प्राप्ति

यदि सेवना विफल होती है (अनपेक्षित घटना होती है), तो संदेश को विलंब से डाला जाएगा, अगली पुन:प्राप्ति की प्रतीक्षा करता है। पुन:प्राप्ति के लिए प्रयोजन वाली समय का प्रारूप max_attempts द्वारा नियंत्रित होता है, और retry_seconds और max_attempts से विलंबन द्वारा नियंत्रित होता है। उदाहरण के लिए, यदि max_attempts 5 है, retry_seconds 10 है, तो पहली पुन:प्राप्ति के लिए अंत्यत: का अंतराल 1*10 सेकंड होता है, दूसरी पुन:प्राप्ति के लिए संघा का अंतराल 2*10 सेकंड होता है, तीसरी पुन:प्राप्ति के लिए संंतराल 3*10 सेकंड होता है, इसी प्रकार से पुन:प्राप्ति 5 बार कराने तक। यदि max_attempts सेट किए गए बार से अधिक होते हैं, तो संदेश को 'redis-queue-failed' की विफलता कतार में डाल दिया जाता है।

संदेश प्रेषित (सिंक्रनाइज़ेशन)

ध्यान दें
webman/redis >= 1.2.0, पर आश्रित है

<?php
namespace app\controller;

use support\Request;
use Webman\RedisQueue\Redis;

class Index
{
    public function queue(Request $request)
    {
        // कतार नाम
        $queue = 'send-mail';
        // डेटा, सीधे सरणी पास कर सकते हैं, सीरीकरण की आवश्यकता नहीं है
        $data = ['to' => 'tom@gmail.com', 'content' => 'hello'];
        // संदेश प्रेषित
        Redis::send($queue, $data);
        // विलंबित संदेश प्रेषित, संदेश 60 सेकंड बाद प्रसंस्करण किया जाएगा
        Redis::send($queue, $data, 60);

        return response('रेडिस कतार परीक्षण');
    }

}

प्रेषण सफल होने पर Redis::send() सच मान लेता है, अन्यथा यह झूठा मान देता है या अनियन्त्रितता को फेंकता है।

संकेत
विलंबित कतार संन्देश समय में अंतराल हो सकता है, उदाहरण के लिए प्रसंस्करण की गति भेद उत्ती, जिसका परिणाम संदेशों को देरी हो सकती है, इससे प्रतिस्पर्धा करने के लिए, अधिक से अधिक सेवना प्रक्रियाओं को खोलना कटियान।

संदेश प्रेषित (असिंक्रोनस)

<?php
namespace app\controller;

use support\Request;
use Webman\RedisQueue\Client;

class Index
{
    public function queue(Request $request)
    {
        // कतार नाम
        $queue = 'send-mail';
        // डेटा, सीधे सरणी पास कर सकते हैं, सीरीकरण की आवश्यकता नहीं है
        $data = ['to' => 'tom@gmail.com', 'content' => 'hello'];
        // संदेश प्रेषित
        Client::send($queue, $data);
        // विलंबित संदेश प्रेषित, संदेश 60 सेकंड बाद प्रसंस्करण किया जाएगा
        Client::send($queue, $data, 60);

        return response('रेडिस कतार परीक्षण');
    }

}

Client::send() कोई वापसी मूल्य नहीं है, यह असिंक्रोनस प्रेषण का हिस्सा होता है, जो संदेश की सौ प्रतिशत रेडिस तक पहुंचना की गारंटी नहीं देता है।

संकेत
Client::send() का सिद्धांत है कि यह स्थानीय मेमोरी में एक मेमोरी कतार बनाता है, और इसे असिंक्रोनस रूप से रेडिस में समकलीन कर देता है (समकलीनता की गति बहुत तेज होती है, प्रति सेकंड लगभग 1 लाख संदेश होते हैं)। यदि प्रक्रियाओं को पुनरारंभ करना पड़ता है, और यह याद किया जाए, तो संदेश हानि हो सकती है। Client::send() असिंक्रोनस संदेश के लिए उपयुक्त है।

संकेत
Client::send() असिंक्रोनस होता है, यह केवल workerman के चल रहे माहौल में उपयोग किया जा सकता है, कमांड लाइन स्क्रिप्ट में Redis::send() से प्रतिस्थापन करें।

अन्य परियोजनाओं में संदेश प्रेषित करें

कभी-कभी आपको अन्य परियोजनाओं में संदेश प्रेषित करना हो सकता है और webman\redis-queue का उपयोग नहीं कर सकते हैं, तब आप निम्नलिखित फ़ंक्शन का उपयोग करके कतार में संदेश प्रेषित कर सकते हैं।

function redis_queue_send($redis, $queue, $data, $delay = 0) {
    $queue_waiting = '{redis-queue}-waiting';
    $queue_delay = '{redis-queue}-delayed';
    $now = time();
    $package_str = json_encode([
        'id'       => rand(),
        'time'     => $now,
        'delay'    => $delay,
        'attempts' => 0,
        'queue'    => $queue,
        'data'     => $data
    ]);
    if ($delay) {
        return $redis->zAdd($queue_delay, $now + $delay, $package_str);
    }
    return $redis->lPush($queue_waiting.$queue, $package_str);
}

जहां, पैरामीटर $redis रेडिस उदाहरण है। उदाहरण के लिए, रेडिस विस्तार के उपयोग का अनुकरण निम्नलिखित हो सकता है:

$redis = new Redis;
$redis->connect('127.0.0.1', 6379);
$queue = 'user-1';
$data= ['कुछ', 'डेटा'];
redis_queue_send($redis, $queue, $data);

उपभोक्ता

उपभोक्ता प्रक्रिया कॉन्फ़िग फ़ाइल है config/plugin/webman/redis-queue/process.php
उपभोक्ता निर्देशिका है app/queue/redis/ में।

php webman redis-queue:consumer my-send-mail कमांड चलाएं तो फ़ाइल app/queue/redis/MyMailSend.php बन जाएगी।

सुझाव
अगर कमांड उपलब्ध नहीं है तो आप स्वयं फ़ाइल बना सकते हैं।

<?php

namespace app\queue\redis;

use Webman\RedisQueue\Consumer;

class MyMailSend implements Consumer
{
    // कतार का नाम
    public $queue = 'send-mail';

    // कनेक्शन नाम, plugin/webman/redis-queue/redis.php में उपलब्ध कनेक्शन के लिए`
    public $connection = 'default';

    // उपभोग करें
    public function consume($data)
    {
        // अपडेट करने की आवश्यकता नहीं है
        var_export($data); // आउटपुट ['to' => 'tom@gmail.com', 'content' => 'hello']
    }
}

ध्यान दें
उपभोग के दौरान अप्रत्याशित और त्रुटि ना उछाली गई हो तो उपभोग सफल माना जाएगा, अन्यथा उपभोग असफल होगा और पुन: प्रयास कतार में जाएगा।
रेडिस-कतार में एक मान्यता (ack) तंत्र नहीं है, आप इसे स्वत: मान्यता (अप्रत्याशित, त्रुटि नहीं हुई हो) के रूप में देख सकते हैं। यदि उपभोग प्रक्रिया में वर्तमान संदेश को असफल चिह्नित करना चाहती है, तो आप स्वत: अप्रत्याशित उछाल सकते हैं, जिससे वर्तमान संदेश पुन: प्रयास कतार में जाए। वास्तव में, यह एक मान्यता (ack) तंत्र के समान है।

सुझाव
उपभोक्ता कई सर्वरों और प्रक्रियाओं का समर्थन करता है, और एक ही संदेश दोहराया नहीं जाएगा। उपभोग किए गए संदेश को स्वचालित रूप से कतार से हटा देगा, किसी भी प्रकार से हस्ताक्षर से हटा देने की आवश्यकता नहीं है।

सुझाव
नए कतार जोड़ने के लिए process.php में कॉन्फ़िगरेशन में परिवर्तन नहीं करना पड़ता, नए कतार उपभोगी के लिए, केवल app/queue/redis में संबंधित Consumer कक्ष जोड़ना होगा, और Consumer वर्ग का गुणक उपभोग करने के लिए कतार का नाम निर्दिष्ट करेगा।

सुझाव
विंडोज उपयोगकर्ताओं को php windows.php कमांड से webman को शुरू करना होगा, अन्यथा वह उपभोग प्रक्रिया शुरू नहीं होगी।

अलग-अलग कतारों के लिए अलग-अलग उपभोग प्रक्रिया सेट करें

सामान्यत: सभी उपभोगकर्ता एक ही उपभोग प्रक्रिया का उपयोग करते हैं। लेकिन कभी-कभी हमें कुछ कतारों को अलग करना पड़ता है, उदाहरण के लिए धीमी व्यापार को एक समूह प्रक्रिया में उपभोग करना। इसके लिए हम उपभोक्ता को दो निर्देशिकाओं में विभाजित कर सकते हैं, उदाहरण के लिए app_path() . '/queue/redis/fast' और app_path() . '/queue/redis/slow' (ध्यान दें कि उपभोगकर्ता क्लास के नेमस्पेस को संबंधित रूप में बदलना होगा)। इसके लिए कॉन्फ़िगरेशन न्मे यह रहता है:

return [
    ...यहां अन्य कॉन्फ़िगरेशन छोड़ दी गई है...

    'redis_consumer_fast'  => [
        'handler'     => Webman\RedisQueue\Process\Consumer::class,
        'count'       => 8,
        'constructor' => [
            // उपभोक्ता कक्ष निर्देशिका
            'consumer_dir' => app_path() . '/queue/redis/fast'
        ]
    ],
    'redis_consumer_slow'  => [
        'handler'     => Webman\RedisQueue\Process\Consumer::class,
        'count'       => 8,
        'constructor' => [
            // उपभोक्ता कक्ष निर्देशिका
            'consumer_dir' => app_path() . '/queue/redis/slow'
        ]
    ]
];

इस निर्देशिका विभाजन और संबंधित कॉन्फ़िगरेशन के माध्यम से हम आसानी से विभिन्न उपभोगकर्ता के लिए अलग-अलग उपभोग प्रक्रिया सेट कर सकते हैं।

अनेक redis कॉन्फ़िगरेशन

कॉन्फ़िगरेशन

config/plugin/webman/redis-queue/redis.php

<?php
return [
    'default' => [
        'host' => 'redis://192.168.0.1:6379',
        'options' => [
            'auth' => null,       // पासवर्ड, स्ट्रिंग प्रकार, वैकल्पिक पैरामीटर
            'db' => 0,            // डेटाबेस
            'max_attempts'  => 5, // उपभोग असफल होने के बाद, पुन: प्रयास की संख्या
            'retry_seconds' => 5, // पुन: प्रयास का अंतराल, सेकंड में
        ]
    ],
    'other' => [
        'host' => 'redis://192.168.0.2:6379',
        'options' => [
            'auth' => null,       // पासवर्ड, स्ट्रिंग प्रकार, वैकल्पिक पैरामीटर
            'db' => 0,             // डेटाबेस
            'max_attempts'  => 5, // उपभोग असफल होने के बाद, पुन: प्रयास की संख्या
            'retry_seconds' => 5, // पुन: प्रयास का अंतराल, सेकंड में
        ]
    ],
];

संदर्भ में एक other नाम के रेडिस कॉन्फ़िगरेशन को जोड़ा गया है।

अनेक redis संदेश भेजना

// `default` के नाम की कतार में संदेश भेजें
Client::connection('default')->send($queue, $data);
Redis::connection('default')->send($queue, $data);
// समान है
Client::send($queue, $data);
Redis::send($queue, $data);

// `other` के नाम की कतार में संदेश भेजें
Client::connection('other')->send($queue, $data);
Redis::connection('other')->send($queue, $data);

अनेक redis उपभोग

उपभोग कॉन्फ़िगरेशन में other के नाम की कतार संदेश भेजें

namespace app\queue\redis;

use Webman\RedisQueue\Consumer;

class SendMail implements Consumer
{
    // कोन्यूम करने के लिए कतार का नाम
    public $queue = 'send-mail';

    // === यहां उसे 'other' के नाम की उपभोग परिपत्रिका के लिए सेट करें ===
    public $connection = 'other';

    // उपभोग
    public function consume($data)
    {
        // अपडेट करने की आवश्यकता नहीं है
        var_export($data);
    }
}

सामान्य प्रश्न

Workerman\Redis\Exception: Workerman Redis Wait Timeout (600 seconds) त्रुटि क्यों हो रही है?

यह त्रुटि केवल असिंक्रोनस डिलीवरी इंटरफेस Client::send() में होगी। असिंक्रोनस डिलीवरी सबसे पहले संदेश को स्थानीय मेमोरी में सहेजेगी, जब प्रक्रिया खाली होगी, तो मैसेज को रेडिस को भेज देगी। अगर रेडिस को संदेश प्राप्ति गति संदेश उत्पादन गति से धीमी होती है, या प्रक्रिया नेति व्यापार में व्यस्त होकर मेमोरी के संदेश को रेडिस को समकीकरण करने के लिए पर्याप्त समय नहीं है, तो संदेश पर दबाव पैदा होगा। अगर संदेश को 600 सेकंड से अधिक समय तक दबावित किया जाता है, तो यह त्रुटि उत्पन्न होगी।

समाधान: संदेश को डिलीवरी करने के लिए सिंक्रोनस डिलीवरी इंटरफेस Redis::send() का उपयोग करें।