Hiredis: أضف مثال كود لـ pub / sub

تم إنشاؤها على ١٥ يوليو ٢٠١١  ·  17تعليقات  ·  مصدر: redis/hiredis

التعليق الأكثر فائدة

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "hiredis/hiredis.h"
#include "hiredis/async.h"
#include "hiredis/adapters/libevent.h"

void onMessage(redisAsyncContext *c, void *reply, void *privdata) {
    redisReply *r = reply;
    if (reply == NULL) return;

    if (r->type == REDIS_REPLY_ARRAY) {
        for (int j = 0; j < r->elements; j++) {
            printf("%u) %s\n", j, r->element[j]->str);
        }
    }
}

int main (int argc, char **argv) {
    signal(SIGPIPE, SIG_IGN);
    struct event_base *base = event_base_new();

    redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
    if (c->err) {
        printf("error: %s\n", c->errstr);
        return 1;
    }

    redisLibeventAttach(c, base);
    redisAsyncCommand(c, onMessage, NULL, "SUBSCRIBE testtopic");
    event_base_dispatch(base);
    return 0;
}

ال 17 كومينتر

أعتقد أنه اقتراح جيد. أنا في حيرة من أمري بشأن pub / sub في كتابة التعليمات البرمجية العملية

+1 لهذا ، أواجه صعوبات مع حانة / فرعية غير متزامنة

تم وضع علامة على ng .

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "hiredis/hiredis.h"
#include "hiredis/async.h"
#include "hiredis/adapters/libevent.h"

void onMessage(redisAsyncContext *c, void *reply, void *privdata) {
    redisReply *r = reply;
    if (reply == NULL) return;

    if (r->type == REDIS_REPLY_ARRAY) {
        for (int j = 0; j < r->elements; j++) {
            printf("%u) %s\n", j, r->element[j]->str);
        }
    }
}

int main (int argc, char **argv) {
    signal(SIGPIPE, SIG_IGN);
    struct event_base *base = event_base_new();

    redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
    if (c->err) {
        printf("error: %s\n", c->errstr);
        return 1;
    }

    redisLibeventAttach(c, base);
    redisAsyncCommand(c, onMessage, NULL, "SUBSCRIBE testtopic");
    event_base_dispatch(base);
    return 0;
}

في Ubuntu 14.04 ، يجب تثبيت مكتبات libevent-dev لتجميع هذا المثال بنجاح. أيضًا ، يجب تمرير علامة -levent أثناء التجميع.

تكمن المشكلة في التوثيق في أنه لم يتم كتابته في أي مكان يمكنك فيه الاشتراك في شيء ما ، ولكن بعد ذلك لا يمكنك فعل أي شيء آخر غير الاشتراك في أحداث أخرى.

جرب شيئًا مثل

redisAsyncCommand(c, onMessage, NULL, "SUBSCRIBE testtopic");
redisAsyncCommand(c, onAnotherMessage, NULL, "SUBSCRIBE anothertopic");
redisAsyncCommand(c, onReply, NULL, "SET toto 5");
redisAsyncCommand(c, onReply, NULL, "PUBLISH testtopic \"hello\"");
redisAsyncCommand(c, onReply, NULL, "GET toto");

ولن يعمل سوى الأمرين الأولين فقط. رد الآخر بـ REDIS_OK لكن رد النداء onReply() يحصل على رد NULL .

الطريقة الوحيدة للقيام بالأشياء بشكل صحيح هي استخدام سياقين redis ، أحدهما للمشتركين (والمراقبة) والآخر للبقية. ربما يجب تحديث المستند ليعكس هذا القيد؟

هل يوجد مستند لكل واجهة برمجة تطبيقات؟

كيف يمكنك التقاط حدث عندما يتم إغلاق المقبس في النهاية؟

كيف يمكنك التقاط حدث عندما يتم إغلاق المقبس في النهاية؟

أو كيف تكتشف بسرعة انتهاء المهلة وإعادة اتصال جديد؟ على سبيل المثال ، إذا كان جدار الحماية بينهما يغلق الاتصال ويسقط الحزم بعد ذلك.

من خلال الاشتراك فقط في هذا الاتصال ، يجعل من المستحيل كما أفهم إرسال شيء للتحقق من المهلات. أيضًا ، لا يبدو أن عمليات الاحتفاظ بصلاحيات TCP موجودة مع ASYNC وعلى أي حال يصعب تكوينها بشكل صحيح على نظام التشغيل Linux داخل حاوية عامل إرساء على سبيل المثال (الفواصل الزمنية ، إعادة المحاولة ، إلخ.)

عادةً مع مآخذ TCP يمكن أن يكون لديك مهلة قصيرة للقراءة / الكتابة على المقبس وبعد إرسال شيء يمكنك معرفة ما إذا كانت مهلة ومحاولة إعادة الاتصال بخادم آخر بسرعة أو القيام بشيء آخر ...

إذا كان هناك شيء آخر يمكنه إرسال أمر ping بشكل غير متزامن وتكوين مهلات القراءة / الكتابة لتشغيل عمليات قطع الاتصال التي ستكون رائعة.

تضمين التغريدة
في تطبيقي الخاص ، استخدمت redisAsyncSetDiconnectCallback ولم أبحث في آلية كيفية عمل ذلك.
https://github.com/nidhhoggr/twemproxy_sentinel/commit/602e07cfdbd57a307ff008e8e9d41909ac34b004

في حالتي ، لا يبدو أن حدث قطع الاتصال يتم إطلاقه بسرعة كافية (أو لا يتم إطلاقه على الإطلاق في بعض الحالات) لهذه الحالة التي أسميها دائمًا "فصل صامت" ، بشكل عام ، يستغرق الأمر وقتًا طويلاً (لقد انتظرت أكثر من 5 دقائق ولم أتلق الحدث مطلقًا ، ولكن بعد 10-15 دقيقة حصلت أخيرًا على واحدة)

بعد قراءة المزيد حول الموضوع ، لاحظت أنه لا يزال بإمكانك تنفيذ أمر PINGs أثناء الاشتراك ، ووجدت أن هذا المنشور يشير إلى أنه يمكنك الاشتراك في حدث استجابة PING الخاص بك كما لو كانت رسالة منشورة:
https://github.com/redis/hiredis/issues/351

ما يبدو أنه يعمل بشكل جيد الآن هو إرسال PINGs على سبيل المثال بفاصل زمني 1 ثانية ، وإذا لم تستقبل استجابة ping بعد الآن (أو سمحت بحد تحمل معين) ، فأنت تفترض أن الاتصال قد توقف ، قم بالتنظيف ، ثم أعد الاتصال. هذا يبدو أكثر قوة وسرعة.

باستخدام libevent و hiredis ، يمكنك تنفيذ تنفيذ الاشتراك غير المتزامن الكامل باستخدام أحداث المؤقت لـ PING أثناء التعامل مع تسليم الرسائل العادي بشكل غير متزامن.

تضمين التغريدة
كان هذا مفيدًا جدًا!
بأي فرصة ، هل حاولت استخدام نفس آلية سياق redisAsyncCommand / Async لإشعارات أحداث مساحة المفاتيح؟
أحاول أن أجعل هذا الجزء يعمل ؛ ولكن للأسف لم تصل الرسائل.

هل جربت هذا؟

redis-cli config set notify-keyspace-events KEA
redisAsyncCommand(c, subscribeCallback, NULL, "PSUBSCRIBE __key*__:*");

@ joe-at-startupmedia
شكرا! لقد جربت هذا بالفعل .. ويبدو أن كل ما سأحصل عليه هو أول استجابة من psubscribe.
لا يتم تلقي أي تحديثات في البيانات بالفعل في رد الاتصال.
هنا رمز عينة:

"

عرّف SUBSCRIBE_CHANNEL "اشتراك URLC_Updates"

عرّف الاشتراك "PSUBSCRIBE '__key __: '"

حدد SCAN_DB "SCAN٪ d COUNT 100"

حدد QUERY_KEY "GET٪ s"

فارغ
onPubsubMessage (redisAsyncContext * c ، باطل * رد ، باطل * بيانات خاصة)
{
redisReply * r = (redisReply *) رد ؛
إذا (رد == NULL) العودة ؛

/* What if reply type is something else... */
if (r->type == REDIS_REPLY_ARRAY) {

    for (int j = 0; j < r->elements; j++) {
        if (r->element[j]->type == REDIS_REPLY_STRING) { 
            myPubsubFile.open(PUBSUB_FILE, fstream::in | fstream::out | fstream::app);
            myPubsubFile << r->element[j]->str << endl;
            myPubsubFile.close();
        } else if (r->element[j]->type == REDIS_REPLY_INTEGER) {
            cout << "Integer : "<< r->element[j]->integer << endl;
        }
    }
}
return;

}
فارغ
onKeyspaceMessage (redisAsyncContext * c ، باطل * رد ، باطل * بيانات خاصة)
{
redisReply * r = (redisReply *) رد ؛
إذا (رد == NULL) يعود ؛

cout << "Got keyspace event notification from REDIS.. " << endl;

/* What if reply type is something else... */
if (r->type == REDIS_REPLY_ARRAY) {
    cout << "Type is an array.. " << endl;
    cout << "Number of elements here: " << r->elements << endl;

    for (int j = 0; j < r->elements; j++) {
        cout << "\t\t Type for element : " << r->element[j]->type << endl;
        if (r->element[j]->type == REDIS_REPLY_STRING) {
            cout << "\t\t\t" << r->element[j]->str << endl;
        } else if (r->element[j]->type == REDIS_REPLY_INTEGER) {
            cout << "\t\t\t" << "Integer : "<< r->element[j]->integer << endl;
        }   
    }   
} else {
    cout << "This is the type for response : " << r->type << endl;
}   
return;

}
فارغ*
pubsubRecipient (void * arg)
{
هيكل event_base * base = event_base_new () ؛

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
    printf("error: %s\n", c->errstr);
    return NULL;
}   

redisLibeventAttach(c, base);
redisAsyncCommand(c, onPubsubMessage    , NULL, SUBSCRIBE_CHANNEL);
redisAsyncCommand(c, onKeyspaceMessage  , NULL, SUBSCRIBE_KEYEVENT);

"

ملاحظة: جزء التكوين ، الذي يمكّن إشعارات مسافة المفاتيح في REDIS ، في عملية منفصلة ؛ ويمكنني رؤية تأثير هذا التكوين ، عندما أقوم بتشغيل مثيل redis-cli في محطة منفصلة.

عفوًا إذا فاتني شيء هنا ولكن سلسلة اشتراكك في keyevent هي:

 "PSUBSCRIBE 'key*:*'"

ألا ينبغي تغييره إلى ما يلي لمطابقة هذا النمط؟

"PSUBSCRIBE __key*__:*"

أوهك .. شيء غريب يحدث مع هذا المحرر ... كانت الخطوط السفلية المحيطة بالمفتاح موجودة عندما قمت بنسخ ولصق الكود الخاص بي.

ومع ذلك ، يبدو أن المشكلة كانت -> '' <- (علامات اقتباس مفردة) تحيط بنمطي _ _ المفتاح * _ _.
لا يقبلها redis-cli دون أي مشاكل ؛ ولكن عندما نرسله عبر أمر redis ، هناك خطأ ما هنا.

الذهاب من خلال القضايا القديمة. تمت إضافة مثال منذ العصور إلى Wiki (شكرًاaluiken)

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات