public static void EndUpdate(this IUpdateable updateable, System.Threading.CancellationToken token) { if (Common.IDisposedExtensions.IsNullOrDisposed(updateable)) { throw new System.ArgumentNullException(); //return default(System.Threading.CancellationToken); } //Ensure a token if (object.ReferenceEquals(token, null)) { return; } //That came from out cancellation source if (token.Equals(updateable.UpdateTokenSource.Token).Equals(false)) { throw InvalidStateException; } // check for manually removed state or a call without an update.. //if(m_Update.Wait(1, token)) { would check that the event was manually cleared... } // acknowledge cancellation if (token.IsCancellationRequested) { throw new System.OperationCanceledException(token); } //Allow threads to modify updateable.ManualResetEvent.Set(); //To unblocked }
/// <summary>Send an HTTP request as an asynchronous operation.</summary> /// <returns>Returns <see cref="T:System.Threading.Tasks.Task`1" />.The task object representing the asynchronous operation.</returns> /// <param name="request">The HTTP request message to send.</param> /// <param name="cancellationToken">The cancellation token to cancel operation.</param> /// <exception cref="T:System.ArgumentNullException">The <paramref name="request" /> was null.</exception> public override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { if (request == null) { throw new ArgumentNullException("request"); } if (request.RequestUri == null && BaseAddress == null) { throw new InvalidOperationException("The request URI must either be set or BaseAddress must be set"); } if (disposed) { throw new ObjectDisposedException(GetType().FullName); } hasKickStarted = true; PrepareMessage(request); //Get Request Options RequestOptions requestOptions = GetRequestOptions(request); var messageProperties = GetMessagingProperties(requestOptions); //Determine if message expects a response TimeSpan requestTimeout = GetRequestTimeout(requestOptions); //TODO: expectingResponse has a slightly different meaning in publisher confirms //where timespan may be longer than zero but MessageExpectsReply is false //in which case the timeout only applies to how long to wait for the publisher confirmation. bool expectingResponse = requestTimeout != TimeSpan.Zero && GetExpectsReply(request); //Declare messaging resources ExpectedResponse arrival = null; AmqpModelContainer model = null; bool modelClosed = false; string correlationId = null; //Get channel pool and decide on RPC strategy var pool = connectionMgr.GetConnectedPool(); IRPCStrategy rpcStrategy = pool.IsDirectReplyToCapable && !Settings.DisableDirectReplies ? directStrategy : callbackStrategy; try { #region Ensure CallbackQueue is started (If Using CallbackQueue Strategy) rpcStrategy.StartStrategy(pool, expectingResponse); #endregion #region Populate BasicProperties //Fill BasicProperties BasicProperties basicProperties = new BasicProperties(); //Set message delivery mode -- Make message persistent if either: // 1. Properties.Persistent is true // 2. messagingConfig.PersistentMessages is true and Properties.Persistent is null // 3. messagingConfig.PersistentMessages is true and Properties.Persistent is true if (messageProperties.Persistent == true || (messagingConfig.PersistentMessages && messageProperties.Persistent != false)) { basicProperties.Persistent = true; } //Set Exchange Headers var exchangeHeaders = messageProperties.Headers ?? messageMapper.GetHeaders(request); if (exchangeHeaders != null) { basicProperties.Headers = exchangeHeaders; } if (expectingResponse) { //Set CorrelationId correlationId = correlationIdGen.GetNextId(); basicProperties.CorrelationId = correlationId; //Set Expiration if messageProperties doesn't override Client.Timeout, RequestOptions and MessageMapper. if (!messageProperties.Expiration.HasValue && requestTimeout != System.Threading.Timeout.InfiniteTimeSpan && (messagingConfig.MessageExpires == null || messagingConfig.MessageExpires(request))) { if (requestTimeout.TotalMilliseconds > Int32.MaxValue) { basicProperties.Expiration = Int32.MaxValue.ToString(); } else { basicProperties.Expiration = ((int)requestTimeout.TotalMilliseconds).ToString(); } } } else if (!messageProperties.Expiration.HasValue && (messagingConfig.MessageExpires == null || messagingConfig.MessageExpires(request))) { //Request has a zero timeout and the message mapper indicates it should expire and messageproperties expiration is not set: //Set the expiration to zero which means RabbitMQ will only transmit if there is a consumer ready to receive it. //If there is no ready consumer, RabbitMQ drops the message. See https://www.rabbitmq.com/ttl.html basicProperties.Expiration = "0"; } //Set expiration if set in message properties if (messageProperties.Expiration.HasValue) { if (messageProperties.Expiration != System.Threading.Timeout.InfiniteTimeSpan) { var expiration = messageProperties.Expiration.Value.Duration(); if (expiration.TotalMilliseconds > Int32.MaxValue) { basicProperties.Expiration = Int32.MaxValue.ToString(); } else { basicProperties.Expiration = ((int)expiration.TotalMilliseconds).ToString(); } } else { //Infinite Timespan indicates that message should never expire basicProperties.ClearExpiration(); } } #endregion #region Get Ready to Send Message model = rpcStrategy.GetModel(pool, false); var serviceName = (requestOptions == null || requestOptions.ServiceName == null) ? (messageMapper.GetServiceName(request) ?? String.Empty).Trim() : requestOptions.ServiceName.Trim(); RedeclareExchangesAndQueues(model, serviceName); //TODO: Check if cancellation token was set before operation even began var taskSource = new TaskCompletionSource <HttpResponseMessage>(); var exchangeKind = ExchangeKind.Direct; //TODO: Get ExchangeKind from CLient.Settings.ExchangeKind //TODO: Pull exchangeName from a concurrent dictionary that has a key of serviceName, exchangeKind //exchangeKind could be an index into arrays that have concurrentDictionaries. var exchangeName = AmqpUtils.GetExchangeName(messagingConfig, serviceName, exchangeKind); #endregion #region Start waiting for response //Start waiting for response if a request timeout is set. if (expectingResponse) { //TODO: Better to just check if cancellationHasbeen requested instead of checking if it's None if (!cancellationToken.Equals(System.Threading.CancellationToken.None)) { //TODO: Have cancellationtokens cancel event trigger callbackHandle //In fact turn this whole thing into an extension } arrival = rpcStrategy.PrepareForResponse(correlationId, basicProperties, model, request, requestTimeout, cancellationToken, taskSource); } #endregion #region Send Message //TODO: Implement routing to a different exchangeKind via substituting exchangeName //Send message model.Channel.BasicPublish(exchangeName, messageProperties.RoutingKey ?? messageMapper.GetRoutingKey(request, exchangeKind) ?? AmqpUtils.GetWorkQueueRoutingKey(), basicProperties, request.ToHttpRequestPacket().Serialize()); //Close channel if (!expectingResponse || rpcStrategy.ReturnModelAfterSending) { CloseAmqpModel(model); modelClosed = true; } #endregion #region Cleanup if not expecting response //Exit with OK result if no request timeout was set. if (!expectingResponse) { //TODO: Investigate adding a publisher confirm for zero timeout messages so we know that RabbitMQ did pick up the message before replying OK. //Might add extra complexity to this class. //Zero timespan means the client isn't interested in a response taskSource.SetResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK) { Content = _emptyByteArrayContent }); rpcStrategy.CleanupMessagingResources(correlationId, arrival); } #endregion return(taskSource.Task); } catch (Exception ex) { //TODO: Log this if (model != null && !modelClosed) { if (expectingResponse && model.Flags == ChannelFlags.RPC || model.Flags == ChannelFlags.RPCWithPublisherConfirms) { //Model might still be in use in waiting thread and so unsafe to be recycled model.Discard = true; } CloseAmqpModel(model); } rpcStrategy.CleanupMessagingResources(correlationId, arrival); if (ex is HttpRequestException) { throw; } else { throw GetWrappedException("An error occurred while sending the request.", ex); } } }
public static bool UnderModification(this IUpdateable updateable, System.Threading.CancellationToken token) { return(object.ReferenceEquals(token, null).Equals(false) && Common.IDisposedExtensions.IsNullOrDisposed(updateable).Equals(false) && token.Equals(updateable.UpdateTokenSource.Token)); }