/// <summary> /// Create a subscriptionId that is unique per grainId, grainType, namespace combination. /// </summary> /// <param name="grainIdTypeCode"></param> /// <param name="streamId"></param> /// <returns></returns> private Guid MakeSubscriptionGuid(int grainIdTypeCode, StreamId streamId) { // next 2 shorts ing guid are from namespace hash uint namespaceHash = JenkinsHash.ComputeHash(streamId.Namespace); byte[] namespaceHashByes = BitConverter.GetBytes(namespaceHash); short s1 = BitConverter.ToInt16(namespaceHashByes, 0); short s2 = BitConverter.ToInt16(namespaceHashByes, 2); // Tailing 8 bytes of the guid are from the hash of the streamId Guid and a hash of the provider name. // get streamId guid hash code uint streamIdGuidHash = JenkinsHash.ComputeHash(streamId.Guid.ToByteArray()); // get provider name hash code uint providerHash = JenkinsHash.ComputeHash(streamId.ProviderName); // build guid tailing 8 bytes from grainIdHash and the hash of the provider name. var tail = new List <byte>(); tail.AddRange(BitConverter.GetBytes(streamIdGuidHash)); tail.AddRange(BitConverter.GetBytes(providerHash)); // make guid. // - First int is grain type // - Two shorts from namespace hash // - 8 byte tail from streamId Guid and provider name hash. return(SubscriptionMarker.MarkAsImplictSubscriptionId(new Guid(grainIdTypeCode, s1, s2, tail.ToArray()))); }
/// <summary> /// Create a subscriptionId that is unique per grainId, grainType, namespace combination. /// </summary> private Guid MakeSubscriptionGuid(GrainType grainType, InternalStreamId streamId) { // next 2 shorts inc guid are from namespace hash uint namespaceHash = JenkinsHash.ComputeHash(streamId.GetNamespace()); byte[] namespaceHashByes = BitConverter.GetBytes(namespaceHash); short s1 = BitConverter.ToInt16(namespaceHashByes, 0); short s2 = BitConverter.ToInt16(namespaceHashByes, 2); // Tailing 8 bytes of the guid are from the hash of the streamId Guid and a hash of the provider name. // get streamId guid hash code uint streamIdGuidHash = JenkinsHash.ComputeHash(streamId.StreamId.Key.Span); // get provider name hash code uint providerHash = JenkinsHash.ComputeHash(streamId.ProviderName); // build guid tailing 8 bytes from grainIdHash and the hash of the provider name. var tail = new List <byte>(); tail.AddRange(BitConverter.GetBytes(streamIdGuidHash)); tail.AddRange(BitConverter.GetBytes(providerHash)); // make guid. // - First int is grain type // - Two shorts from namespace hash // - 8 byte tail from streamId Guid and provider name hash. var id = new Guid((int)JenkinsHash.ComputeHash(grainType.ToString()), s1, s2, tail.ToArray()); var result = SubscriptionMarker.MarkAsImplictSubscriptionId(id); return(result); }
public GuidId CreateSubscriptionId(IAddressable requesterAddress, StreamId streamId) { GrainId grainId = GrainExtensions.GetGrainId(requesterAddress); Guid subscriptionId; if (!implicitPubSub.TryGetImplicitSubscriptionGuid(grainId, streamId, out subscriptionId)) { subscriptionId = SubscriptionMarker.MarkAsExplicitSubscriptionId(Guid.NewGuid()); } return(GuidId.GetGuidId(subscriptionId)); }
private async Task <bool> ErrorProtocol(StreamConsumerData consumerData, Exception exceptionOccured, bool isDeliveryError, IBatchContainer batch, StreamSequenceToken token) { // for loss of client, we just remove the subscription if (exceptionOccured is ClientNotAvailableException) { logger.LogWarning( (int)ErrorCode.Stream_ConsumerIsDead, "Consumer {Consumer} on stream {StreamId} is no longer active - permanently removing Consumer.", consumerData.StreamConsumer, consumerData.StreamId); pubSub.UnregisterConsumer(consumerData.SubscriptionId, consumerData.StreamId).Ignore(); return(true); } // notify consumer about the error or that the data is not available. await OrleansTaskExtentions.ExecuteAndIgnoreException( () => DeliverErrorToConsumer( consumerData, exceptionOccured, batch)); // record that there was a delivery failure if (isDeliveryError) { await OrleansTaskExtentions.ExecuteAndIgnoreException( () => streamFailureHandler.OnDeliveryFailure( consumerData.SubscriptionId, streamProviderName, consumerData.StreamId, token)); } else { await OrleansTaskExtentions.ExecuteAndIgnoreException( () => streamFailureHandler.OnSubscriptionFailure( consumerData.SubscriptionId, streamProviderName, consumerData.StreamId, token)); } // if configured to fault on delivery failure and this is not an implicit subscription, fault and remove the subscription if (streamFailureHandler.ShouldFaultSubsriptionOnError && !SubscriptionMarker.IsImplicitSubscription(consumerData.SubscriptionId.Guid)) { try { // notify consumer of faulted subscription, if we can. await OrleansTaskExtentions.ExecuteAndIgnoreException( () => DeliverErrorToConsumer( consumerData, new FaultedSubscriptionException(consumerData.SubscriptionId, consumerData.StreamId), batch)); // mark subscription as faulted. await pubSub.FaultSubscription(consumerData.StreamId, consumerData.SubscriptionId); } finally { // remove subscription RemoveSubscriber_Impl(consumerData.SubscriptionId, consumerData.StreamId); } return(true); } return(false); }
private async Task <bool> ErrorProtocol(StreamConsumerData consumerData, Exception exceptionOccured, bool isDeliveryError, IBatchContainer batch, StreamSequenceToken token) { // notify consumer about the error or that the data is not available. await OrleansTaskExtentions.ExecuteAndIgnoreException( () => DeliverErrorToConsumer( consumerData, exceptionOccured, batch)); // record that there was a delivery failure if (isDeliveryError) { await OrleansTaskExtentions.ExecuteAndIgnoreException( () => streamFailureHandler.OnDeliveryFailure( consumerData.SubscriptionId, streamProviderName, consumerData.StreamId, token)); } else { await OrleansTaskExtentions.ExecuteAndIgnoreException( () => streamFailureHandler.OnSubscriptionFailure( consumerData.SubscriptionId, streamProviderName, consumerData.StreamId, token)); } // if configured to fault on delivery failure and this is not an implicit subscription, fault and remove the subscription if (streamFailureHandler.ShouldFaultSubsriptionOnError && !SubscriptionMarker.IsImplicitSubscription(consumerData.SubscriptionId.Guid)) { try { // notify consumer of faulted subscription, if we can. await OrleansTaskExtentions.ExecuteAndIgnoreException( () => DeliverErrorToConsumer( consumerData, new FaultedSubscriptionException(consumerData.SubscriptionId, consumerData.StreamId), batch)); // mark subscription as faulted. await pubSub.FaultSubscription(consumerData.StreamId, consumerData.SubscriptionId); } finally { // remove subscription RemoveSubscriber_Impl(consumerData.SubscriptionId, consumerData.StreamId); } return(true); } return(false); }
internal bool IsImplicitSubscriber(GuidId subscriptionId, StreamId streamId) { return(SubscriptionMarker.IsImplicitSubscription(subscriptionId.Guid)); }
public GuidId CreateSubscriptionId(InternalStreamId streamId, IStreamConsumerExtension streamConsumer) { Guid subscriptionId = SubscriptionMarker.MarkAsExplicitSubscriptionId(Guid.NewGuid()); return(GuidId.GetGuidId(subscriptionId)); }
private async Task RunConsumerCursor(StreamConsumerData consumerData, IStreamFilterPredicateWrapper filterWrapper) { try { // double check in case of interleaving if (consumerData.State == StreamConsumerDataState.Active || consumerData.Cursor == null) { return; } consumerData.State = StreamConsumerDataState.Active; while (consumerData.Cursor != null && consumerData.Cursor.MoveNext()) { IBatchContainer batch = null; Exception ex; Task deliveryTask; bool deliveryFailed = false; try { batch = consumerData.Cursor.GetCurrent(out ex); } catch (DataNotAvailableException dataNotAvailable) { ex = dataNotAvailable; } // Apply filtering to this batch, if applicable if (filterWrapper != null && batch != null) { try { // Apply batch filter to this input batch, to see whether we should deliver it to this consumer. if (!batch.ShouldDeliver( consumerData.StreamId, filterWrapper.FilterData, filterWrapper.ShouldReceive)) { continue; // Skip this batch -- nothing to do } } catch (Exception exc) { var message = string.Format("Ignoring exception while trying to evaluate subscription filter function {0} on stream {1} in PersistentStreamPullingAgentGrain.RunConsumerCursor", filterWrapper, consumerData.StreamId); logger.Warn((int)ErrorCode.PersistentStreamPullingAgent_13, message, exc); } } if (batch != null) { deliveryTask = AsyncExecutorWithRetries.ExecuteWithRetries(i => DeliverBatchToConsumer(consumerData, batch), AsyncExecutorWithRetries.INFINITE_RETRIES, (exception, i) => !(exception is DataNotAvailableException), config.MaxEventDeliveryTime, DefaultBackoffProvider); } else if (ex == null) { deliveryTask = consumerData.StreamConsumer.CompleteStream(consumerData.SubscriptionId); } else { // If data is not avialable, bring cursor current if (ex is DataNotAvailableException) { consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId.Guid, consumerData.StreamId.Namespace, null); } // Notify client of error. deliveryTask = DeliverErrorToConsumer(consumerData, ex, null); } try { numSentMessagesCounter.Increment(); await deliveryTask; } catch (Exception exc) { var message = string.Format("Exception while trying to deliver msgs to stream {0} in PersistentStreamPullingAgentGrain.RunConsumerCursor", consumerData.StreamId); logger.Error((int)ErrorCode.PersistentStreamPullingAgent_14, message, exc); deliveryFailed = true; } // if we failed to deliver a batch if (deliveryFailed && batch != null) { // notify consumer of delivery error, if we can. await OrleansTaskExtentions.ExecuteAndIgnoreException(() => DeliverErrorToConsumer(consumerData, new StreamEventDeliveryFailureException(consumerData.StreamId), batch)); // record that there was a delivery failure await streamFailureHandler.OnDeliveryFailure(consumerData.SubscriptionId, streamProviderName, consumerData.StreamId, batch.SequenceToken); // if configured to fault on delivery failure and this is not an implicit subscription, fault and remove the subscription if (streamFailureHandler.ShouldFaultSubsriptionOnError && !SubscriptionMarker.IsImplicitSubscription(consumerData.SubscriptionId.Guid)) { try { // notify consumer of faulted subscription, if we can. DeliverErrorToConsumer(consumerData, new FaultedSubscriptionException(consumerData.SubscriptionId, consumerData.StreamId), batch) .Ignore(); // mark subscription as faulted. await pubSub.FaultSubscription(consumerData.StreamId, consumerData.SubscriptionId); } finally { // remove subscription RemoveSubscriber_Impl(consumerData.SubscriptionId, consumerData.StreamId); } return; } } } consumerData.State = StreamConsumerDataState.Inactive; } catch (Exception exc) { // RunConsumerCursor is fired with .Ignore so we should log if anything goes wrong, because there is no one to catch the exception logger.Error((int)ErrorCode.PersistentStreamPullingAgent_15, "Ignored RunConsumerCursor Error", exc); throw; } }