Hiredis: Tambahkan contoh kode untuk pub/sub

Dibuat pada 15 Jul 2011  ·  17Komentar  ·  Sumber: redis/hiredis

ng

Komentar yang paling membantu

#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;
}

Semua 17 komentar

Saya pikir itu saran yang bagus. Saya cukup bingung tentang pub/sub dalam menulis kode praktis

+1 untuk ini, saya mengalami kesulitan dengan async libev pub/sub

Ditandai untuk 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;
}

Di Ubuntu 14.04, perpustakaan libevent-dev perlu diinstal agar berhasil mengkompilasi contoh ini. Juga, flag -levent perlu diteruskan selama kompilasi.

Masalah dalam dokumentasi adalah bahwa tidak tertulis di mana pun bahwa Anda dapat BERLANGGANAN untuk sesuatu, tetapi kemudian tidak dapat melakukan apa pun selain berlangganan acara lain.

Cobalah sesuatu seperti

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

Dan hanya 2 perintah pertama yang akan berfungsi. Respon lain dengan REDIS_OK tapi onReply() callback mendapat NULL menjawab.

Satu-satunya cara untuk melakukan sesuatu dengan benar adalah dengan menggunakan 2 konteks redis, satu untuk pelanggan (dan MONITOR), yang lain untuk sisanya. Mungkin doc harus diperbarui untuk mencerminkan batasan ini?

Apakah ada dokumen untuk SETIAP api?

Bagaimana Anda menangkap suatu peristiwa ketika soket akhirnya ditutup?

Bagaimana Anda menangkap suatu peristiwa ketika soket akhirnya ditutup?

Atau bagaimana Anda mendeteksi batas waktu dengan cepat dan mengulang koneksi baru? Misalnya jika firewall di antaranya menutup koneksi dan menjatuhkan paket setelahnya.

Dengan hanya berlangganan pada koneksi itu, seperti yang saya pahami, tidak mungkin mengirim sesuatu untuk memeriksa batas waktu. Juga TCP keepalives tampaknya tidak ada dengan ASYNC dan bagaimanapun ini sulit untuk dikonfigurasi dengan benar di linux di dalam wadah buruh pelabuhan misalnya (interval, coba lagi, dll.)

Biasanya dengan soket TCP Anda dapat memiliki batas waktu baca/tulis yang singkat pada soket dan setelah Anda mengirim sesuatu, Anda dapat melihat apakah waktu habis dan dengan cepat mencoba menyambung kembali ke server lain atau melakukan sesuatu yang lain ...

Jika ada hal lain yang dapat mengirim perintah ping secara asinkron dan mengonfigurasi batas waktu baca/tulis untuk memicu pemutusan, itu akan menyenangkan.

@gerporgl
Dalam implementasi saya sendiri, saya menggunakan redisAsyncSetDiconnectCallback Saya belum meneliti mekanisme cara kerjanya.
https://github.com/nidhhoggr/twemproxy_sentinel/commit/602e07cfdbd57a307ff008e8e9d41909ac34b004

Dalam kasus saya, acara pemutusan tampaknya tidak diaktifkan cukup cepat (atau tidak sama sekali dalam beberapa kasus) untuk kasus ini dari apa yang saya selalu sebut "pemutusan senyap", secara umum butuh waktu lama (saya menunggu lebih dari 5 menit dan tidak pernah menerima acara, tetapi kemudian setelah 10-15 menit akhirnya saya mendapatkannya)

Setelah membaca lebih banyak tentang subjek, saya perhatikan bahwa Anda masih dapat melakukan perintah PING saat berlangganan, dan menemukan posting ini menyebutkan bahwa Anda dapat berlangganan acara respons PING Anda sendiri seolah-olah itu adalah pesan yang diterbitkan:
https://github.com/redis/hiredis/issues/351

Pada dasarnya apa yang tampaknya berfungsi dengan baik sekarang adalah mengirim PING misalnya pada interval 1 detik, dan jika Anda tidak menerima respons ping lagi (atau Anda mengizinkan ambang toleransi tertentu) maka Anda menganggap koneksi sudah mati, lakukan pembersihan, lalu menyambung kembali. Yang tampaknya jauh lebih kuat dan cepat.

Dengan menggunakan lievent dan hire, Anda dapat melakukan implementasi asinkron berlangganan lengkap menggunakan peristiwa pengatur waktu untuk PING sambil menangani pengiriman pesan normal secara asinkron.

@gerporgl
Ini sangat membantu!
Kebetulan apakah Anda mencoba menggunakan mekanisme konteks redisAsyncCommand/Async yang sama untuk pemberitahuan acara ruang kunci?
Saya mencoba untuk membuat bagian itu bekerja; tapi sayangnya tidak mendapatkan pesan.

Sudahkah Anda mencoba ini?

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

@joe-at-startupmedia
Terima kasih! Saya sudah mencoba ini .. dan sepertinya yang saya dapatkan kembali adalah respons psubscribe pertama.
Pembaruan apa pun dalam data sebenarnya tidak diterima dalam panggilan balik.
Berikut adalah contoh kode:

`

tentukan SUBSCRIBE_CHANNEL "SUBSCRIBE URLC_Updates"

tentukan SUBSCRIBE_KEYEVENT "PSUBSCRIBE '__key __: '"

tentukan SCAN_DB "SCAN %d COUNT 100"

tentukan QUERY_KEY "DAPATKAN %s"

ruang kosong
onPubsubMessage(redisAsyncContext *c, batal *balasan, batal *privdata)
{
redisReply *r = (redisReply *) balasan;
if (balas == NULL) kembali;

/* 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;

}
ruang kosong
onKeyspaceMessage(redisAsyncContext *c, batal *balas, batal *privdata)
{
redisReply *r = (redisReply *) balasan;
if (balas == NULL) kembali;

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;

}
ruang kosong*
pubsubRecipient(void* arg)
{
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 NULL;
}   

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

`

PS Bagian config, yang mengaktifkan notifikasi key-space di REDIS sedang dalam proses terpisah; dan saya dapat melihat efek konfigurasi itu, ketika saya menjalankan instance redis-cli di terminal terpisah.

Maaf Jika saya melewatkan sesuatu di sini tetapi string langganan keyevent Anda adalah:

 "PSUBSCRIBE 'key*:*'"

Haruskah tidak diubah menjadi yang berikut agar sesuai dengan pola itu?

"PSUBSCRIBE __key*__:*"

Ohk .. sesuatu yang aneh terjadi dengan editor ini ... garis bawah di sekitar kunci hadir ketika saya menyalin dan menempelkan kode saya.

namun, sepertinya masalahnya adalah -> ' ' <- (tanda kutip tunggal) di sekitar pola _ _ key * _ _ saya.
redis-cli menerimanya tanpa masalah; tetapi ketika kami mengirimkannya melalui perintah redis, ada yang salah di sini.

Melewati masalah lama. Sebuah contoh telah ditambahkan berabad-abad yang lalu ke Wiki (terima kasih @aluiken)

Apakah halaman ini membantu?
0 / 5 - 0 peringkat