Istnieje wiele sposobów, aby to zrobić. Na przykład można użyć EventingBasicConsumer
wraz z ManualResetEvent
, tak (to tylko w celach demonstracyjnych - lepiej skorzystać z jednej z poniższych metod):
var factory = new ConnectionFactory();
using (var connection = factory.CreateConnection()) {
using (var channel = connection.CreateModel()) {
// setup signal
using (var signal = new ManualResetEvent(false)) {
var consumer = new EventingBasicConsumer(channel);
byte[] messageBody = null;
consumer.Received += (sender, args) => {
messageBody = args.Body;
// process your message or store for later
// set signal
signal.Set();
};
// start consuming
channel.BasicConsume("your.queue", false, consumer);
// wait until message is received or timeout reached
bool timeout = !signal.WaitOne(TimeSpan.FromSeconds(10));
// cancel subscription
channel.BasicCancel(consumer.ConsumerTag);
if (timeout) {
// timeout reached - do what you need in this case
throw new Exception("timeout");
}
// at this point messageBody is received
}
}
}
Jak stwierdzono w komentarzach - jeśli można się spodziewać wielu wiadomości na temat tej samej kolejki , to nie jest najlepszy sposób. Cóż, nie jest to najlepszy sposób w każdym przypadku, zawarłem to tylko po to, aby zademonstrować użycie ManualResetEvent
w przypadku, gdy sama biblioteka nie zapewnia obsługi limitów czasu.
Jeśli robisz wywołanie RPC (zdalne wywoływanie procedury, żądanie-odpowiedź) - możesz użyć SimpleRpcClient
wraz z SimpleRpcServer
po stronie serwera. po stronie klienta będzie wyglądać następująco:
var client = new SimpleRpcClient(channel, "your.queue");
client.TimeoutMilliseconds = 10 * 1000;
client.TimedOut += (sender, args) => {
// do something on timeout
};
var reply = client.Call(myMessage); // will return reply or null if timeout reached
Jeszcze bardziej prosty sposób: używać podstawowego Subscription
klasę (używa tego samego EventingBasicConsumer
wewnętrznie, ale wspiera limity czasu, dzięki czemu nie trzeba realizować siebie), tak:
var sub = new Subscription(channel, "your.queue");
BasicDeliverEventArgs reply;
if (!sub.Next(10 * 1000, out reply)) {
// timeout
}
Pierwsze rozwiązanie jest nieprawidłowe. BasicConsume nie ma gwarancji zatrzymania konsumpcji na BasicCancel, może to zrobić nieco później ze względu na implementację królika w locie (po prostu spróbuj użyć jednej wiadomości na żądanie, a zobaczysz, że w niektórych przypadkach przypiszesz kilka razy komunikat messageBody). Nadal będziesz wymagać zgłaszania nadmiernych wiadomości. Dla drugiego i trzeciego spróbuję teraz:) – eocron
Choć twoja górna część nie ma znaczenia, klasa subskrypcji jest dokładnie tym, czego chciałem! Dziękuję, działa cudownie! Czy możesz edytować odpowiedź, aby inni wiedzieli, że ostatnia została opracowana? – eocron
Mimo to przechowuje kilka wiadomości wewnątrz przez implementację, podczas gdy ja potrzebuję tylko jeden =/ – eocron