private void CoreConnection_Connected(string appId) { try { var exchangeName = Name + ".direct"; var consumer = new ConsumerParam() { ExchangeParam = new ChannelExchangeParam() { Name = exchangeName, Type = ExchangeTypes.EXCHANGETYPE_DIRECT, }, QueueParam = new ChannelQueueParam() { Name = exchangeName + "." + appId, AutoDelete = true } }; CoreConnection.Listen(consumer, (msg) => { var str = Encoding.UTF8.GetString(msg.Content); msg.Ack(); Trace.TraceInformation($"Listen ({Name}): {str}"); if (str == "Exit") { lockEvent.Set(); } if (QuestionAnswerDictionary.ContainsKey(str)) { Say(QuestionAnswerDictionary[str]); if (QuestionAnswerDictionary[str] == "Exit") { lockEvent.Set(); } } else { throw new InvalidOperationException("Неизвестное сообщение"); } }); if (!string.IsNullOrEmpty(SayMessage) && QuestionAnswerDictionary.ContainsKey(SayMessage)) { Say(SayMessage); } } catch (Exception ex) { Trace.TraceError(ex.ToString()); throw; } }
/// <summary> /// Прослушивание очереди сообщений /// </summary> /// <param name="cparam">Парамеры создания обмена, очереди и подписчика</param> /// <param name="callback">Функция обратного вызова при получении сообщения</param> /// <returns></returns> public string Listen(ConsumerParam cparam, Action <ReceivedMessageEventArgs> callback) { if (cparam?.QueueParam == null) { throw new CoreException("QueueParam not declared"); } var default_durable = Configuration.MQ.durable.HasValue ? Configuration.MQ.durable.Value : false; channel.QueueDeclare(cparam.QueueParam.Name, cparam.QueueParam.Durable ?? default_durable, cparam.QueueParam.Exclusive, cparam.QueueParam.AutoDelete, cparam.QueueParam.Arguments); //Queue declare Trace.TraceInformation($"Declare queue [{cparam.QueueParam.Name}]. Options: {cparam.QueueParam.ToJson()}"); if (cparam.ExchangeParam != null) { channel.ExchangeDeclare(cparam.ExchangeParam.Name, cparam.ExchangeParam.Type ?? ExchangeTypes.EXCHANGETYPE_DIRECT, cparam.ExchangeParam.Durable ?? default_durable, cparam.ExchangeParam.AutoDelete, cparam.ExchangeParam.Arguments); //Exchange declare Trace.TraceInformation($"Bind queue [{cparam.QueueParam.Name}] to exchange [{cparam.ExchangeParam.Name}({cparam.ExchangeParam.Type})]. AppId=[{AppId.CurrentUID}] "); //Bind queue and exchange channel.QueueBind(cparam.QueueParam.Name, cparam.ExchangeParam.Name, AppId.CurrentUID); } //create consumer and subscribe var consumer = new EventingBasicConsumer(channel); if (!string.IsNullOrEmpty(cparam.ConsumerTag)) { consumer.ConsumerTag = consumer.ConsumerTag; } consumer.Received += (model, ea) => { if (callback != null) { //Ack Nack with try-catch? check if throw exception var msg = new ReceivedMessageEventArgs(ea, () => { try { channel.BasicAck(ea.DeliveryTag, multiple: false); } catch (Exception ex) { Trace.TraceWarning($"Ask error:{ex}"); } }, (autoRepeat) => { try { channel.BasicNack(ea.DeliveryTag, multiple: false, requeue: autoRepeat); } catch (Exception ex) { Trace.TraceWarning($"Nask error:{ex}"); } }); callback.Invoke(msg); } }; return(channel.BasicConsume(cparam.QueueParam.Name, cparam.AutoAck, consumer)); }
private void Resolver_Started(string obj) { Trace.TraceInformation("Resolver started"); //Self resolving timeout, exiting ... int timeout = Config.Starter.registerselftimeout ?? 10000; var register = Resolver.RegisterSelf(); if (Task.WhenAny(register, Task.Delay(timeout)).Result != register) { throw new CoreException("Resolver self register timeout expired!"); } var links = register.Result; Trace.TraceInformation("Self links resolved"); int queueInc = 2; if (links != null) { foreach (var link in links) { var exchangeName = ExchangeTypes.GetExchangeName(link.name, link.type, null); Trace.TraceInformation($"Bind {exchangeName} start.."); ConsumerParam options = new ConsumerParam(); options.QueueParam = new ChannelQueueParam() { AutoDelete = Config.MQ.autodelete ?? false, }; if (Config.MQ.queue.ttl.HasValue) { options.QueueParam.SetExpiresMs(Config.MQ.queue.ttl.Value); } switch (link.type) { case LinkTypes.LINK_EXCHANGE: { ExchangeConnectionString = exchangeName; options.QueueParam.Name = $"{exchangeName}.{AppId}"; options.ExchangeParam = new ChannelExchangeParam() { Name = exchangeName, AutoDelete = Config.MQ.autodelete ?? false }; if (Config.MQ.exchange.ttl.HasValue) { options.ExchangeParam.SetExpiresMs(Config.MQ.exchange.ttl.Value); } } break; case LinkTypes.LINK_QUEUE: { QueueConnectionString = exchangeName; options.QueueParam.Name = exchangeName; } break; default: { Trace.TraceWarning($"Unknow link type: [{link.type}]"); continue; } } //Максимальный пул одновременных сообщений контролируется параметром ru:spinosa:mq:prefetch //т.е. максимальным числом полученных сообщений оставленных без ответа Connection.Listen(options, (ea) => { Task.Run(() => this.HandleMessage(ea)) .ContinueWith(res => { this.HandleMessageErrors?.Invoke(ea, res.Exception); }, TaskContinuationOptions.OnlyOnFaulted); }); Trace.TraceInformation($"Bind {exchangeName} successed"); queueInc--; } } if (queueInc == 0) { this.running = true; //запускаем обновление кэша только если удалось получить собственные ссылки т.к. это подтверждает, что оператор запущен и имеет смысл к нему обращаться // if (Config.Starter.pingperiod_ms.HasValue) { Trace.TraceInformation($"RunRefreshCache started {Config.Starter.pingperiod_ms.Value}ms"); Resolver.RunRefreshCache(); } Started?.Invoke(AppId); } else { throw new CoreException("Self links bind error: queueInc!=0 "); } }
private void Connection_Connected(string appId) { var refreshInterval = cfg_starter.pingperiod_ms; var cparam = new ConsumerParam() { QueueParam = new ChannelQueueParam() { Name = $"{cfg_starter._this._namespace}.{cfg_starter._this.servicename}.resolver.{appId}", AutoDelete = true, Durable = true }, ExchangeParam = new ChannelExchangeParam() { Name = cfg_starter.responseexchangename, Type = ExchangeTypes.EXCHANGETYPE_DIRECT, AutoDelete = false, Durable = true } }; if (Configuration.MQ.queue.ttl.HasValue) { cparam.QueueParam.SetExpiresMs(Configuration.MQ.queue.ttl.Value); } if (Configuration.MQ.exchange.ttl.HasValue) { cparam.ExchangeParam.SetExpiresMs(Configuration.MQ.exchange.ttl.Value); } Connection.Listen(cparam, (msg) => { //очередь принимает массив ссылок (links) var responceStr = System.Text.Encoding.UTF8.GetString(msg.Content); var responce = responceStr.FromJson <List <ResolverEntry> >(); if (responce?.Any() ?? false) { //по каждой ссылке foreach (var element in responce) { //ключ - имя сервиса с версией var key = GetKey(element.Namespace, element.service, element.version ?? 0); try { if (element.result == true) { var links = element?.link; if (links == null) { throw new CoreException($"Resolver queue: Empty links for service. Key: {key}"); } //если не self очереди - кэшируем if (element.type != CacheItem.SELF_TOKEN) { //создаем элемент в кэше var cache_item = new CacheItem() { Namespace = element.Namespace, service = element.service, version = element.version, sub_version = element.sub_version, self_link = false, links = links }; AddToLinkCache(key, cache_item); } //отвечаем на запросы var tsc = GetPengingContext(key); if (tsc != null) { tsc.SetResult(links.ToArray()); } } else { throw new CoreException($"Resolver queue: response element result is false. Key: {key}"); } } catch (Exception ex) { Trace.TraceWarning(($"Resolver queue error: {ex}")); var tsc = GetPengingContext(key); tsc?.SetException(ex); } finally { RemovePengingElement(key); } } } msg.Ack(); }); Bind = true; //SendToOperator(true).Wait(); //SendToOperator(false).Wait(); Started?.Invoke(AppId); Trace.TraceInformation("Resolver queue created"); }