public async override Task <AckStrategy> InvokeUserMessageHandlerAsync(ConsumerExecutionContext context) { if (logger.IsDebugEnabled()) { logger.DebugFormat("Received message with receivedInfo={receivedInfo}", context.Info); } var ackStrategy = await InvokeUserMessageHandlerInternalAsync(context).ConfigureAwait(false); return((model, tag) => { try { return ackStrategy(model, tag); } catch (Exception exception) { logger.Error( exception, "Unexpected exception when attempting to ACK or NACK, receivedInfo={receivedInfo}", context.Info); } return AckResult.Exception; }); }
public When_a_user_handler_is_executed() { var consumerErrorStrategy = Substitute.For <IConsumerErrorStrategy>(); var eventBus = new EventBus(); var handlerRunner = new HandlerRunner(consumerErrorStrategy, eventBus); Func <byte[], MessageProperties, MessageReceivedInfo, Task> userHandler = (body, properties, info) => Task.Factory.StartNew(() => { deliveredBody = body; deliveredProperties = properties; deliveredInfo = info; }); var consumer = Substitute.For <IBasicConsumer>(); channel = Substitute.For <IModel>(); consumer.Model.Returns(channel); var context = new ConsumerExecutionContext( userHandler, messageInfo, messageProperties, messageBody, consumer); var autoResetEvent = new AutoResetEvent(false); eventBus.Subscribe <AckEvent>(x => autoResetEvent.Set()); handlerRunner.InvokeUserMessageHandler(context); autoResetEvent.WaitOne(1000); }
public override AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { var ex = exception.InnerException; if (ex.GetType() == typeof(HBFlowException)) { return(AckStrategies.NackWithRequeue); } var count = 0; var id = context.Properties.CorrelationId; if (!Keys.ContainsKey(id)) { Keys.Add(id, 0); } Keys.TryGetValue(id, out count); if (count == 0) { LoggerHelper.Error(ex); } count++; Keys[id] = count; return(AckStrategies.NackWithRequeue); }
public override AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { string message; if (!_disposed && !_disposing) { ConsumerException consumerException; switch (exception) { case ConsumerException ce: consumerException = ce; break; case var other: consumerException = new ConsumerException(other); break; } switch (consumerException.InnerException) { case OperationCanceledException _: return(AckStrategies.NackWithRequeue); case UnhandledMessageTypeException _: _logger?.LogError($"Unhandled message type: {context.Properties.Type}"); return(AckStrategies.NackWithoutRequeue); default: var innerException = consumerException.InnerException; var innerInnerException = consumerException.InnerException?.InnerException; if (!string.IsNullOrWhiteSpace(innerException?.Message) || innerInnerException != null) { message = $"Consumer exception: {innerException?.Message}\n{innerException?.StackTrace}"; _logger?.LogError(consumerException, message); } switch (consumerException.InnerException) { case IAckException _: return(AckStrategies.Ack); case INackWithRequeueException _: return(AckStrategies.NackWithRequeue); default: return(AckStrategies.NackWithoutRequeue); } } } message = $"The {nameof(ConsumerErrorStrategy)} has already been disposed, while attempting to handle a " + "consumer error, and the received message ({info}) will be requeued."; _logger?.LogError(message, context.ReceivedInfo); return(AckStrategies.NackWithRequeue); }
public void Should_not_reconnect_if_has_been_disposed() { const string originalMessage = "{ Text:\"Hello World\"}"; var originalMessageBody = Encoding.UTF8.GetBytes(originalMessage); var exception = new Exception("I just threw!"); var context = new ConsumerExecutionContext( (bytes, properties, arg3) => null, new MessageReceivedInfo("consumertag", 0, false, "orginalExchange", "originalRoutingKey", "queue"), new MessageProperties { CorrelationId = "123", AppId = "456" }, originalMessageBody ); connectionFactory = Substitute.For <IConnectionFactory>(); consumerErrorStrategy = new DefaultConsumerErrorStrategy( connectionFactory, Substitute.For <ISerializer>(), Substitute.For <IConventions>(), Substitute.For <ITypeNameSerializer>(), Substitute.For <IErrorMessageSerializer>()); consumerErrorStrategy.Dispose(); var ackStrategy = consumerErrorStrategy.HandleConsumerError(context, exception); connectionFactory.DidNotReceive().CreateConnection(); Assert.Equal(AckStrategies.NackWithRequeue, ackStrategy); }
public override AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { object deathHeaderObject; if (!context.Properties.Headers.TryGetValue("x-death", out deathHeaderObject)) { return(AckStrategies.NackWithoutRequeue); } var deathHeaders = deathHeaderObject as IList; if (deathHeaders == null) { return(AckStrategies.NackWithoutRequeue); } var retries = 0; foreach (IDictionary header in deathHeaders) { var count = int.Parse(header["count"].ToString()); retries += count; } if (retries < 3) { return(AckStrategies.NackWithoutRequeue); } return(base.HandleConsumerError(context, exception)); }
/// <inheritdoc /> public override Task <AckStrategy> InvokeUserMessageHandlerAsync(ConsumerExecutionContext context) { _logger.Debug("Received \n\tRoutingKey: '{0}'\n\tCorrelationId: '{1}'\n\tConsumerTag: '{2}'\n\tDeliveryTag: {3}\n\tRedelivered: {4}", context.Info.RoutingKey, context.Properties.CorrelationId, context.Info.ConsumerTag, context.Info.DeliverTag, context.Info.Redelivered); Task completionTask; try { completionTask = _policy.Execute(() => { var task = context.UserHandler(context.Body, context.Properties, context.Info); if (task.IsFaulted) { throw task.Exception.GetBaseException(); } return(task); }); } catch (Exception exception) { completionTask = Task.FromException(exception); } if (completionTask.Status == TaskStatus.Created) { _logger.Error("Task returned from consumer callback is not started. ConsumerTag: '{0}'", context.Info.ConsumerTag); return(null); } return(completionTask.ContinueWith(task => AckStrategies.Ack)); }
public void SetUp() { //var logger = new ConsoleLogger(); var logger = MockRepository.GenerateStub <IEasyNetQLogger>(); var consumerErrorStrategy = MockRepository.GenerateStub <IConsumerErrorStrategy>(); var eventBus = new EventBus(); handlerRunner = new HandlerRunner(logger, consumerErrorStrategy, eventBus); Func <byte[], MessageProperties, MessageReceivedInfo, Task> userHandler = (body, properties, info) => Task.Factory.StartNew(() => { deliveredBody = body; deliveredProperties = properties; deliveredInfo = info; }); var consumer = MockRepository.GenerateStub <IBasicConsumer>(); channel = MockRepository.GenerateStub <IModel>(); consumer.Stub(x => x.Model).Return(channel).Repeat.Any(); var context = new ConsumerExecutionContext( userHandler, messageInfo, messageProperties, messageBody, consumer); var autoResetEvent = new AutoResetEvent(false); eventBus.Subscribe <AckEvent>(x => autoResetEvent.Set()); handlerRunner.InvokeUserMessageHandler(context); autoResetEvent.WaitOne(1000); }
private string DeclareErrorExchangeQueueStructure(IModel model, ConsumerExecutionContext context) { return("ErrorExchange_" + context.Info.RoutingKey); // DeclareDefaultErrorQueue(model); return(DeclareErrorExchangeAndBindToDefaultErrorQueue(model, context)); }
public When_a_user_handler_is_failed() { consumerErrorStrategy = Substitute.For <IConsumerErrorStrategy>(); consumerErrorStrategy.HandleConsumerError(null, null).ReturnsForAnyArgs(AckStrategies.Ack); var handlerRunner = new HandlerRunner(consumerErrorStrategy); var consumer = Substitute.For <IBasicConsumer>(); channel = Substitute.For <IModel>(); consumer.Model.Returns(channel); context = new ConsumerExecutionContext( async(body, properties, info) => throw new Exception(), messageInfo, messageProperties, messageBody ); var handlerTask = handlerRunner.InvokeUserMessageHandlerAsync(context) .ContinueWith(async x => { var ackStrategy = await x.ConfigureAwait(false); return(ackStrategy(channel, 42)); }, TaskContinuationOptions.ExecuteSynchronously) .Unwrap(); if (!handlerTask.Wait(5000)) { throw new TimeoutException(); } }
public When_a_user_handler_is_cancelled() { consumerErrorStrategy = Substitute.For <IConsumerErrorStrategy>(); var eventBus = new EventBus(); var handlerRunner = new HandlerRunner(consumerErrorStrategy, eventBus); Func <byte[], MessageProperties, MessageReceivedInfo, Task> userHandler = (body, properties, info) => Task.Run(() => throw new OperationCanceledException()); var consumer = Substitute.For <IBasicConsumer>(); var channel = Substitute.For <IModel>(); consumer.Model.Returns(channel); context = new ConsumerExecutionContext(userHandler, messageInfo, messageProperties, messageBody, consumer); var autoResetEvent = new AutoResetEvent(false); eventBus.Subscribe <AckEvent>(x => autoResetEvent.Set()); handlerRunner.InvokeUserMessageHandler(context); autoResetEvent.WaitOne(1000); }
public void SetUp() { var conventions = new Conventions { ConsumerTagConvention = () => consumerTag }; consumerErrorStrategy = MockRepository.GenerateStub <IConsumerErrorStrategy>(); consumerErrorStrategy.Stub(x => x.HandleConsumerError(null, null)) .IgnoreArguments() .WhenCalled(i => { basicDeliverEventArgs = (ConsumerExecutionContext)i.Arguments[0]; raisedException = (Exception)i.Arguments[1]; }); consumerErrorStrategy.Stub(x => x.PostExceptionAckStrategy()).Return(PostExceptionAckStrategy.ShouldAck); mockBuilder = new MockBuilder(x => x .Register <IConventions>(_ => conventions) .Register(_ => consumerErrorStrategy) //.Register<IEasyNetQLogger>(_ => new ConsoleLogger()) ); mockBuilder.Bus.Subscribe <MyMessage>(subscriptionId, message => { throw originalException; }); const string text = "Hello there, I am the text!"; originalMessage = new MyMessage { Text = text }; var body = new JsonSerializer().MessageToBytes(originalMessage); // deliver a message mockBuilder.Consumers[0].HandleBasicDeliver( consumerTag, deliveryTag, false, // redelivered typeName, "#", new BasicProperties { Type = typeName, CorrelationId = correlationId }, body); // wait for the subscription thread to handle the message ... var autoResetEvent = new AutoResetEvent(false); var handlerExecutionContext = (HandlerRunner)mockBuilder.ServiceProvider.Resolve <IHandlerRunner>(); handlerExecutionContext.SynchronisationAction = () => autoResetEvent.Set(); autoResetEvent.WaitOne(1000); }
/// <summary> /// 声明重试队列 /// </summary> /// <param name="model"></param> /// <param name="context"></param> /// <returns></returns> private string DeclareReTryExchangeWithQueue(IModel model, ConsumerExecutionContext context) { var reTryExchangeName = $"ReTry_{context.Info.Exchange}"; var reTryQueueName = $"ReTry_{context.Info.Queue}"; var routingKey = string.IsNullOrEmpty(context.Info.RoutingKey) ? context.Info.Queue.Substring(context.Info.Exchange.Length + 1) : context.Info.RoutingKey; DeclareAndBindExchangeWithQueue(model, reTryExchangeName, reTryQueueName, routingKey); return(reTryExchangeName); }
public AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { //FileNotFoundException if (exception.GetType().Equals(typeof(FileNotFoundException))) { return(AckStrategies.NackWithoutRequeue); } return(AckStrategies.NackWithRequeue); }
public When_the_handler_throws_an_exception() { var conventions = new Conventions(new TypeNameSerializer()) { ConsumerTagConvention = () => consumerTag }; consumerErrorStrategy = Substitute.For <IConsumerErrorStrategy>(); consumerErrorStrategy.HandleConsumerError(null, null) .ReturnsForAnyArgs(i => { basicDeliverEventArgs = (ConsumerExecutionContext)i[0]; raisedException = (Exception)i[1]; return(AckStrategies.Ack); }); mockBuilder = new MockBuilder(x => x .Register <IConventions>(_ => conventions) .Register(_ => consumerErrorStrategy) //.Register<IEasyNetQLogger>(_ => new ConsoleLogger()) ); mockBuilder.Bus.Subscribe <MyMessage>(subscriptionId, message => { throw originalException; }); const string text = "Hello there, I am the text!"; originalMessage = new MyMessage { Text = text }; var body = new JsonSerializer(new TypeNameSerializer()).MessageToBytes(originalMessage); // deliver a message mockBuilder.Consumers[0].HandleBasicDeliver( consumerTag, deliveryTag, false, // redelivered typeName, "#", new BasicProperties { Type = typeName, CorrelationId = correlationId }, body); // wait for the subscription thread to handle the message ... var autoResetEvent = new AutoResetEvent(false); mockBuilder.EventBus.Subscribe <AckEvent>(x => autoResetEvent.Set()); autoResetEvent.WaitOne(1000); }
private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception) { var error = new Error { ErrorMessage = exception.Message, RawMessage = context.Body }; return(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(error))); }
public AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { logger.Error( exception, "Exception thrown by subscription callback, receivedInfo={receivedInfo}, properties={properties}", context.Info, context.Properties ); return(AckStrategies.NackWithRequeue); }
private string DeclareErrorExchangeAndBindToDefaultErrorQueue(IModel model, ConsumerExecutionContext context) { var originalRoutingKey = context.Info.RoutingKey; return(this.errorExchanges.GetOrAdd(originalRoutingKey, (Func <string, string>)(_ => { var exchange = this.conventions.ErrorExchangeNamingConvention(context.Info); model.ExchangeDeclare(exchange, "direct", true); model.QueueBind(this.conventions.ErrorQueueNamingConvention(), exchange, originalRoutingKey); return exchange; }))); }
private string DeclareErrorExchangeAndBindToDefaultErrorQueue(IModel model, ConsumerExecutionContext context) { var originalRoutingKey = context.Info.RoutingKey; return(errorExchanges.GetOrAdd(originalRoutingKey, _ => { var exchangeName = conventions.ErrorExchangeNamingConvention(context.Info); model.ExchangeDeclare(exchangeName, ExchangeType.Direct, durable: true); model.QueueBind(conventions.ErrorQueueNamingConvention(), exchangeName, originalRoutingKey); return exchangeName; })); }
private string DeclareErrorExchangeAndBindToDefaultErrorQueue(IModel model, ConsumerExecutionContext context) { var originalRoutingKey = context.Info.RoutingKey; return(_errorExchanges.GetOrAdd(originalRoutingKey, _ => { var exchangeName = _conventions.ErrorExchangeNamingConvention(context.Info); model.ExchangeDeclare(exchangeName, ExchangeType.Direct, durable: true); model.QueueBind( $"{(string.IsNullOrEmpty(context.Info.Queue) ? context.Info.RoutingKey : context.Info.ConsumerTag)}_deadletter", exchangeName, originalRoutingKey); return exchangeName; })); }
public override AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (exception == null) { throw new ArgumentNullException(nameof(exception)); } try { if (context.Properties.Headers.ContainsKey(RetryConstants.RetryCountKey)) { var retryCount = Convert.ToInt32((long)context.Properties.Headers[RetryConstants.RetryCountKey]); if (retryCount > this.maxAttemptsCount) { this.logger.ErrorWrite( "EasyNetQ Consumer Error Handler: Skip republish to dead-letter queue - max attempts count exceeded."); //LOG MESSAGE HERE return(AckStrategies.Ack); } } this.Connect(); using (var model = this.connection.CreateModel()) { var exchange = this.DeclareErrorExchangeQueueStructure(model, context); var errorMessage = this.CreateErrorMessage(context, exception); var basicProperties = model.CreateBasicProperties(); basicProperties.SetPersistent(true); basicProperties.Type = this.typeNameSerializer.Serialize(typeof(Error)); model.BasicPublish(exchange, context.Info.RoutingKey, basicProperties, errorMessage); } } catch (BrokerUnreachableException ex) { this.logger.ErrorWrite("EasyNetQ Consumer Error Handler cannot connect to Broker\n" + this.CreateConnectionCheckMessage(), new object[0]); } catch (OperationInterruptedException ex) { this.logger.ErrorWrite("EasyNetQ Consumer Error Handler: Broker connection was closed while attempting to publish Error message.\n" + $"Message was: '{(object)ex.Message}'\n" + this.CreateConnectionCheckMessage(), new object[0]); } catch (Exception ex) { this.logger.ErrorWrite("EasyNetQ Consumer Error Handler: Failed to publish error message\nException is:\n" + (object)ex, new object[0]); } return(AckStrategies.Ack); }
private static void RetryMessage(ConsumerExecutionContext context, IModel model, MessageProperties properties, int flrRetry) { // Ensure and update the retrycount properties.Headers.Remove("easynetq.retry.count"); properties.Headers.Add("easynetq.retry.count", flrRetry); // Copy all properties to BasicProperties for the Rabbit var basicProperties = model.CreateBasicProperties(); properties.CopyTo(basicProperties); // Resend the message model.BasicPublish(context.Info.Exchange, context.Info.RoutingKey, basicProperties, context.Body); }
private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception) { var messageAsString = Encoding.UTF8.GetString(context.Body); var error = new Error { RoutingKey = context.Info.RoutingKey, Exchange = context.Info.Exchange, Exception = exception.ToString(), Message = messageAsString, DateTime = DateTime.UtcNow, BasicProperties = context.Properties }; return(serializer.MessageToBytes(error)); }
private void SendMessageToErrorQueue(ConsumerExecutionContext context, Exception exception, IModel model, MessageProperties properties) { var errorExchange = DeclareErrorExchangeQueueStructure(model, context); _logger.InfoWrite( $"(DEAD LETTERED) Second Level Retry max reached for message of type [{properties.Type}], message is sent to dead letter queue: [{errorExchange}]."); var messageBody = CreateDefaultErrorMessage(context, exception.InnerException); var errorProperties = model.CreateBasicProperties(); properties.CopyTo(errorProperties); errorProperties.Persistent = true; errorProperties.Type = _typeNameSerializer.Serialize(typeof(RabbitErrorMessage)); model.BasicPublish(errorExchange, context.Info.RoutingKey, errorProperties, messageBody); }
private async Task <AckStrategy> InvokeUserMessageHandlerInternalAsync(ConsumerExecutionContext context) { try { await _policy.ExecuteAsync(async() => { await context.UserHandler(context.Body, context.Properties, context.Info).ConfigureAwait(false); }); } catch (Exception exception) { logger.Error(exception, "Consumer error strategy has failed"); return(AckStrategies.NackWithoutRequeue); } return(AckStrategies.Ack); }
public When_using_default_consumer_error_strategy() { var customConventions = new Conventions(new DefaultTypeNameSerializer()) { ErrorQueueNamingConvention = info => "CustomEasyNetQErrorQueueName", ErrorExchangeNamingConvention = info => "CustomErrorExchangePrefixName." + info.RoutingKey }; mockBuilder = new MockBuilder(); var connectionConfiguration = new ConnectionConfiguration(); var connection = new PersistentConnection(connectionConfiguration, mockBuilder.ConnectionFactory, new EventBus()); errorStrategy = new DefaultConsumerErrorStrategy( connection, new JsonSerializer(), customConventions, new DefaultTypeNameSerializer(), new DefaultErrorMessageSerializer(), connectionConfiguration ); const string originalMessage = ""; var originalMessageBody = Encoding.UTF8.GetBytes(originalMessage); var context = new ConsumerExecutionContext( (bytes, properties, info, cancellation) => Task.FromResult(AckStrategies.Ack), new MessageReceivedInfo("consumerTag", 0, false, "orginalExchange", "originalRoutingKey", "queue"), new MessageProperties { CorrelationId = string.Empty, AppId = string.Empty }, originalMessageBody ); try { errorAckStrategy = errorStrategy.HandleConsumerError(context, new Exception()); cancelAckStrategy = errorStrategy.HandleConsumerCancelled(context); } catch (Exception) { // swallow } }
public void Should_handle_an_exception_by_writing_to_the_error_queue() { const string originalMessage = "{ Text:\"Hello World\"}"; var originalMessageBody = Encoding.UTF8.GetBytes(originalMessage); var exception = new Exception("I just threw!"); var context = new ConsumerExecutionContext( (bytes, properties, arg3) => null, new MessageReceivedInfo("consumertag", 0, false, "orginalExchange", "originalRoutingKey", "queue"), new MessageProperties { CorrelationId = "123", AppId = "456" }, originalMessageBody, MockRepository.GenerateStub <IBasicConsumer>() ); consumerErrorStrategy.HandleConsumerError(context, exception); Thread.Sleep(100); // Now get the error message off the error queue and assert its properties using (var connection = connectionFactory.CreateConnection()) using (var model = connection.CreateModel()) { var getArgs = model.BasicGet(conventions.ErrorQueueNamingConvention(), true); if (getArgs == null) { Assert.Fail("Nothing on the error queue"); } else { var message = serializer.BytesToMessage <Error>(getArgs.Body); message.RoutingKey.ShouldEqual(context.Info.RoutingKey); message.Exchange.ShouldEqual(context.Info.Exchange); message.Message.ShouldEqual(originalMessage); message.Exception.ShouldEqual("System.Exception: I just threw!"); message.DateTime.Date.ShouldEqual(DateTime.Now.Date); message.BasicProperties.CorrelationId.ShouldEqual(context.Properties.CorrelationId); message.BasicProperties.AppId.ShouldEqual(context.Properties.AppId); } } }
private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception) { var @string = Encoding.UTF8.GetString(context.Body); if (context.Properties?.Headers != null) { if (context.Properties.Headers.ContainsKey(RetryConstants.RetryCountKey)) { var retryCount = Convert.ToInt32((long)context.Properties.Headers[RetryConstants.RetryCountKey]); context.Properties.Headers[RetryConstants.RetryCountKey] = ++retryCount; } else { context.Properties.Headers.Add(RetryConstants.RetryCountKey, 0); } } var aggregateException = exception as AggregateException; var resultException = aggregateException != null ? aggregateException.InnerException : exception; try { var message = new Error() { RoutingKey = context.Info.RoutingKey, Exchange = context.Info.Exchange, Exception = resultException.ToString(), Message = @string, DateTime = DateTime.Now, BasicProperties = context.Properties }; return(this.serializer.MessageToBytes(message)); } catch (JsonSerializationException ex) { this.logger.ErrorWrite(ex); throw; } catch (Exception ex) { this.logger.ErrorWrite(ex); throw; } }
public override AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { var ex = exception; if (ex is AggregateException) { ex = ex.InnerException; } if (ex is NoAckWithRequeueException) { return(AckStrategies.NackWithRequeue); } if (ex is NoAckWithoutRequeueException) { return(AckStrategies.NackWithoutRequeue); } return(base.HandleConsumerError(context, exception)); }
public void SetUp() { var customConventions = new Conventions(new TypeNameSerializer()) { ErrorQueueNamingConvention = () => "CustomEasyNetQErrorQueueName", ErrorExchangeNamingConvention = info => "CustomErrorExchangePrefixName." + info.RoutingKey }; mockBuilder = new MockBuilder(); errorStrategy = new DefaultConsumerErrorStrategy( mockBuilder.ConnectionFactory, new JsonSerializer(new TypeNameSerializer()), MockRepository.GenerateStub <IEasyNetQLogger>(), customConventions, new TypeNameSerializer(), new DefaultErrorMessageSerializer()); const string originalMessage = ""; var originalMessageBody = Encoding.UTF8.GetBytes(originalMessage); var context = new ConsumerExecutionContext( (bytes, properties, arg3) => null, new MessageReceivedInfo("consumerTag", 0, false, "orginalExchange", "originalRoutingKey", "queue"), new MessageProperties { CorrelationId = string.Empty, AppId = string.Empty }, originalMessageBody, MockRepository.GenerateStub <IBasicConsumer>() ); try { errorAckStrategy = errorStrategy.HandleConsumerError(context, new Exception()); cancelAckStrategy = errorStrategy.HandleConsumerCancelled(context); } catch (Exception) { // swallow } }