简体   繁体   中英

How can I keep a Channel alive after an error?

I want to delete several queues on our RabbitMQ server and have some code that looks like this:

string[] queuesToDelete = new[] {
  "QueueThatExists1",
  "QueueThatDoesn'tExist", // this queue causes an error - which I expect
  "QueueThatExists2" };    // this queue also errors - which I don't expect

IConnectionFactory factory = ...
using (IModel = factory.CreateModel()) {
  foreach (string queue in queuesToDelete) {
    try {
      model.QueueDelete(queue);
      Console.WriteLine("Queue {0} deleted");
    } catch (Exception e) {
      Console.WriteLine("Queue {0} could not be deleted because {1}", queue, e);
    }
  }
}

However I get this as output:

Queue QueueThatExists1 deleted
Queue QueueThatDoesn'tExist could not be deleted because Queue Not Found
Queue QueueThatExists2 could not be deleted because Already Closed

I have changed the code to look more like this (which works as I expect):

string[] queuesToDelete = new[] {
  "QueueThatExists1",
  "QueueThatDoesn'tExist", // this queue causes an error - which I expect
  "QueueThatExists2" };    // this queue also errors - which I don't expect

IConnectionFactory factory = ...
IModel model;
try {
  model = factory.CreateModel();
  foreach (string queue in queuesToDelete) {
    try {
      model.QueueDelete(queue);
      Console.WriteLine("Queue {0} deleted");
    } catch (Exception e) {
      Console.WriteLine("Queue {0} could not be deleted because {1}", queue, e);
      // reset the connection
      model.Dispose();
      model = factory.CreateModel();
    }
  } finally {
    if (model != null)
      model.Dispose();
  }
}

However this looks bad. I have removed a using statement and hand rolled the same thing with a try - finally block. It feels like I am fighting the API. Question: Is there a more elegant way of achieving the same result?

I notice that RabbitMQ for java has lyra and autorecovery , but cannot find anything similar for C#.

Check out project EasyNetQ .

EasyNetQ implement subscriber reconnection ( EasyNetQ doc ).

Instead of a try/catch I recommend checking if that you're interested in exists. You can do this with the API. Here is our method to do that:

  private bool DoesSomethingExist(string something, string queueOrExchange)
    {
        var connectionInfo = GetRabbitConnectionInfo();
        var url = string.Format("{0}/{1}/{2}/{3}", connectionInfo.APIUrl, queueOrExchange, connectionInfo.VirtualHostName, something);
        using (var client = new HttpClient())
        {
            var byteArray = Encoding.ASCII.GetBytes(string.Format("{0}:{1}", connectionInfo.UserName, connectionInfo.Password));
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
            var response = client.GetAsync(url).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                return true;
            }
            if (response.StatusCode == HttpStatusCode.NotFound)
            {
                return false;
            }

            var content = response.Content;
            throw new Exception(string.Format("Unhandled API response code of {0}, content: {1}", response.StatusCode, content));
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM