예제 #1
0
        /// <summary>
        /// Updates the metadata on the BLOB to reflect the poisoned monitoring data
        /// </summary>
        /// <param name="blobClient">The BLOB to associate the metadata with</param>
        /// <param name="data">The poisoned message tracking contents</param>
        /// <param name="cancellationToken">A token to monitor for abort and cancellation requests</param>
        /// <returns>True if successful</returns>
        private async Task <bool> SetPoisonMessageContentsAsync(BlobClient blobClient, PoisonData data, CancellationToken cancellationToken)
        {
            var success = false;

            var metadata = new Dictionary <string, string>()
            {
                { SequenceNumber, (data.SequenceNumber ?? -1L).ToString(CultureInfo.InvariantCulture) },
                { ReceivedCount, data.ReceiveCount.ToString(CultureInfo.InvariantCulture) },
                { PartitionId, data.PartitionId }
            };

            try
            {
                using (_updateBlobTiming.Time())
                {
                    await blobClient.SetMetadataAsync(metadata, cancellationToken : cancellationToken).ConfigureAwait(false);

                    Logger.LogDebug("Metadata set for partition {partitionId}", data.PartitionId);
                }

                success = true;
            }
            catch (RequestFailedException e) when(e.ErrorCode == BlobErrorCode.BlobNotFound)
            {
                Logger.LogInformation("Blob not found partition {partitionId}", data.PartitionId);

                using var blobContent = new MemoryStream(Array.Empty <byte>());

                using (_updateBlobTiming.Time())
                {
                    await blobClient.UploadAsync(blobContent, metadata : metadata, cancellationToken : cancellationToken).ConfigureAwait(false);

                    Logger.LogDebug("Blob updated for partition {partitionId}", data.PartitionId);
                }

                success = true;
            }
            catch (RequestFailedException e) when(e.ErrorCode == BlobErrorCode.ContainerNotFound)
            {
                Logger.LogInformation("Container not found {partitionId}", data.PartitionId);

                await Client.CreateIfNotExistsAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

                using var blobContent = new MemoryStream(Array.Empty <byte>());

                using (_updateBlobTiming.Time())
                {
                    await blobClient.UploadAsync(blobContent, metadata : metadata, cancellationToken : cancellationToken).ConfigureAwait(false);

                    Logger.LogDebug("Blob uploaded for partition {partitionId}", data.PartitionId);
                }

                success = true;
            }

            return(success);
        }
        /// <summary>
        /// Updates the checkpoint for the partition
        /// </summary>
        /// <param name="eventData">The event data to checkpoint to</param>
        /// <param name="cancellationToken">A token to monitor for abort requests.</param>
        /// <returns>True if the checkpointing was successful.</returns>
        public async Task <bool> CheckpointAsync(EventData eventData, CancellationToken cancellationToken)
        {
            var success = false;

            try
            {
                _logger.LogInformation("Checkpointing for partition {partitionId}", PartitionId);

                _checkpointCounter.Increment();

                using (_checkpointTiming.Time())
                {
                    await _checkpointManager.UpdateCheckpointAsync(eventData, this, cancellationToken).ConfigureAwait(false);
                }

                success = true;
                _logger.LogDebug("Finished checkpointing for partition {partitionId}", PartitionId);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error checkpointing for partition {partitionId}", PartitionId);
            }

            return(success);
        }
예제 #3
0
        /// <summary>
        /// Authenticates the client credentials against the hub
        /// </summary>
        /// <param name="request">The request</param>
        /// <param name="cancellationToken">A token to monitor for abort requests</param>
        /// <returns>The authentication response</returns>
        protected virtual async Task <AuthenticationResponsePayload> AuthenticateClientAsync(HttpRequest request, CancellationToken cancellationToken)
        {
            AuthenticationResponsePayload response = null;

            using (var reader = new StreamReader(request.Body))
            {
                var requestPayload = JsonConvert.DeserializeObject <AuthenticationRequestPayload>(reader.ReadToEnd());

                using (_authenticationTiming.Time())
                {
                    if (await AuthenticateAsync(request, requestPayload, cancellationToken).ConfigureAwait(false))
                    {
                        var accessToken = SharedAccessTokens.GenerateSasToken($"{_sasTokenScheme}://{requestPayload.UserName}", _sasSigningKey, _sasTokenPolicyName, (int)_sasTokenTimeout.TotalSeconds);

                        response = new AuthenticationResponsePayload
                        {
                            TokenType   = "bearer",
                            AccessToken = accessToken
                        };
                    }
                }
            }

            return(response);
        }
예제 #4
0
        /// <inheritdoc />
        public async Task <EpochOperationResult> AddOrUpdateEpochAsync(EpochValue value, bool force, CancellationToken cancellationToken)
        {
            EpochOperationResult results;

            using (_logger.BeginScope("Update epoch"))
            {
                _logger.LogInformation("Adding epoch: {partitionId}, forced: {force}", value.PartitionId, force);

                CloudBlockBlob epochBlob = _consumerGroupDirectory.GetBlockBlobReference(value.PartitionId);

                try
                {
                    _epochUpdateCounter.Increment();
                    AccessCondition accessCondition = force ? AccessCondition.GenerateLeaseCondition("*") : AccessCondition.GenerateLeaseCondition(value.ConcurrencyValue);
                    var             content         = JsonConvert.SerializeObject(value);

                    _logger.LogDebug("Writing content to partition {partitionId}, raw: {json}", value.PartitionId, content);

                    using (_storagePerformanceSummary.Time())
                    {
                        await epochBlob.UploadTextAsync(content, _leaseEncoding, accessCondition, _defaultRequestOptions, null).ConfigureAwait(false);
                    }

                    value.ConcurrencyValue = epochBlob.Properties.ETag;
                    _logger.LogDebug("Completed write of epoch to partition {partitionId}", value.PartitionId);

                    results = EpochOperationResult.Success;
                }
                catch (StorageException e) when(e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict)
                {
                    _logger.LogInformation("Epoch content conflict for partition {partitionId}", value.PartitionId);
                    results = EpochOperationResult.Conflict;
                    _epochErrorCounter.Increment();
                }
                catch (Exception e)
                {
                    _epochErrorCounter.Increment();
                    results = EpochOperationResult.Failure;
                    _logger.LogError(e, "Error adding or updating epoch for partition {partitionId}", value.PartitionId);
                }

                return(results);
            }
        }
예제 #5
0
        /// <inheritdoc />
        public virtual async Task <IEnumerable <EventProcessorCheckpoint> > ListCheckpointsAsync(CancellationToken cancellationToken)
        {
            var checkpoints = new List <EventProcessorCheckpoint>();

            _listCheckpointsCounter.Increment();

            using (Logger.BeginScope("Listing checkpoints"))
            {
                // Timing added around loop although not ideal. This is tied the paging async
                using (_listBlobTiming.Time())
                {
                    Logger.LogInformation("Retrieving checkpoints");

                    await foreach (BlobItem blob in Client.GetBlobsAsync(traits: BlobTraits.Metadata, prefix: _checkpointPrefix, cancellationToken: cancellationToken).ConfigureAwait(false))
                    {
                        var partitionId      = blob.Name.Substring(_checkpointPrefix.Length + 1);
                        var startingPosition = default(EventPosition?);

                        Logger.LogDebug("Retrieved blob for partition {partitionId}", partitionId);
                        var sequenceNumber = await GetCheckpointSequenceNumberAsync(partitionId, blob, cancellationToken).ConfigureAwait(false);

                        if (sequenceNumber.HasValue)
                        {
                            Logger.LogDebug("Checkpoint was found with a sequence number of {sequenceNumber}", sequenceNumber);

                            startingPosition = EventPosition.FromSequenceNumber(sequenceNumber.Value, false);

                            checkpoints.Add(new Checkpoint
                            {
                                FullyQualifiedNamespace = _processorClient.FullyQualifiedNamespace,
                                EventHubName            = _processorClient.EventHubName,
                                ConsumerGroup           = _processorClient.ConsumerGroup,
                                PartitionId             = partitionId,
                                StartingPosition        = startingPosition.Value,
                                SequenceNumber          = sequenceNumber
                            });
                        }
                        else
                        {
                            Logger.LogError("An invalid checkpoint was found, no starting position");
                        }
                    }
                }
            }

            return(checkpoints);
        }
예제 #6
0
        /// <summary>
        /// Processes the web socket session
        /// </summary>
        /// <param name="socket">The web socket that is in use</param>
        /// <param name="cancellationToken">A token to monitor for abort requests</param>
        public async Task ProcessAsync(WebSocket socket, CancellationToken cancellationToken)
        {
            using (Logger.BeginScope("Hander Process"))
            {
                Logger.LogInformation("Web socket handlers invoked");

                using (_serviceSessionGauge.TrackExecution())
                {
                    Task receiverTask = null;

                    try
                    {
                        _socket          = socket;
                        LastActivityTime = DateTime.UtcNow;

                        Logger.LogDebug("Web socket receiver starting");
                        receiverTask = ReceiveMessagesAsync(socket, cancellationToken);

                        using (_sessionTimes.Time())
                        {
                            while (SocketState == WebSocketState.Open && LastActivityTime.Add(WebSocketConfiguration.SessionTimeout ?? TimeSpan.FromSeconds(30)) > DateTime.UtcNow)
                            {
                                await IterationAsync(ContainerLifecycle.CancellationToken).ConfigureAwait(false);
                            }
                        }

                        Logger.LogInformation("Web socket session completed");
                    }
                    catch (Exception e)
                    {
                        Logger.LogError(e, "Error processing session, aborting");
                        _errorCounter.Increment();
                    }

                    Logger.LogDebug("Web socket iteration complete, closing");
                    await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Session closed", CancellationToken.None).ConfigureAwait(false);

                    if (receiverTask != null)
                    {
                        await receiverTask.ConfigureAwait(false);
                    }
                }

                Logger.LogInformation("Web socket handlers ending");
            }
        }
예제 #7
0
        /// <summary>
        /// Receive loop for getting messages
        /// </summary>
        /// <param name="socket">The web socket that is associated with the session</param>
        /// <param name="cancellationToken">A token to monitor for abort requests</param>
        private async Task ReceiveMessagesAsync(WebSocket socket, CancellationToken cancellationToken)
        {
            using (Logger.BeginScope("Receive Message Loop"))
            {
                var buffer     = BufferPool.Take();
                var bufferList = new List <(byte[], int)>();
                Task <WebSocketReceiveResult> receiveTask = null;

                while (SocketState == WebSocketState.Open)
                {
                    try
                    {
                        if (receiveTask == null)
                        {
                            receiveTask = socket.ReceiveAsync(buffer, CancellationToken.None);
                        }
                        var completedTask = await Task.WhenAny(receiveTask, Task.Delay(250)).ConfigureAwait(false);

                        if (receiveTask.IsCompleted)
                        {
                            var result = receiveTask.Result;

                            LastActivityTime = DateTime.UtcNow;

                            if (result.Count > 0)
                            {
                                bufferList.Add((buffer, result.Count));
                                buffer = BufferPool.Take();
                            }

                            if (result.EndOfMessage)
                            {
                                var byteCount = 0;

                                foreach (var currentBuffer in bufferList)
                                {
                                    byteCount += currentBuffer.Item2;
                                }

                                var finalBuffer = new byte[byteCount];
                                var position    = 0;

                                foreach (var currentBuffer in bufferList)
                                {
                                    Buffer.BlockCopy(currentBuffer.Item1, 0, finalBuffer, position, currentBuffer.Item2);
                                    position += currentBuffer.Item2;
                                }

                                foreach (var currentBuffer in bufferList)
                                {
                                    BufferPool.Return(currentBuffer.Item1);
                                }

                                bufferList.Clear();

                                try
                                {
                                    using (_receiveTimes.Time())
                                    {
                                        await MessageReceivedAsync(finalBuffer, cancellationToken).ConfigureAwait(false);
                                    }
                                }
                                catch (Exception e)
                                {
                                    _errorCounter.Increment();
                                    Logger.LogError(e, "Error processing received message");
                                }
                            }

                            receiveTask = null;
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.LogError(e, "Error in receive loop");
                        _errorCounter.Increment();

                        if (bufferList.Count > 0)
                        {
                            foreach (var currentBuffer in bufferList)
                            {
                                BufferPool.Return(currentBuffer.Item1);
                            }
                        }
                    }
                }

                if (bufferList.Count > 0)
                {
                    foreach (var currentBuffer in bufferList)
                    {
                        BufferPool.Return(currentBuffer.Item1);
                    }
                }

                BufferPool.Return(buffer);
            }
        }
예제 #8
0
        /// <inheritdoc />
        public async Task <bool> CreateLeaseStoreIfNotExistsAsync()
        {
            bool success;

            using (_logger.BeginScope("Create lease store"))
            {
                _logger.LogInformation("Creating Azure Storage lease store");

                using (_storagePerformanceSummary.Time())
                {
                    success = await _leaseStoreContainer.CreateIfNotExistsAsync(_defaultRequestOptions, _operationContext).ConfigureAwait(false);

                    _logger.LogDebug("Lease store creation results {result}", success);
                }
            }

            return(success);
        }
예제 #9
0
        /// <inheritdoc />
        public async Task <PoisonData> GetPoisonDataAsync(string partitionId, CancellationToken cancellationToken)
        {
            PoisonData data;

            if (!_currentData.TryGetValue(partitionId, out data))
            {
                data = default;
            }

            if (data == default)
            {
                using (Logger.BeginScope("Read Poison Data"))
                {
                    Logger.LogInformation("Reading poison data");

                    var blobName   = string.Format(_blobNameFormatString, partitionId);
                    var blobClient = Client.GetBlobClient(blobName);

                    Response <BlobProperties> response = null;

                    using (_readBlobTiming.Time())
                    {
                        try
                        {
                            response = await blobClient.GetPropertiesAsync(cancellationToken : cancellationToken).ConfigureAwait(false);
                        }
                        catch (RequestFailedException e) when(e.ErrorCode == BlobErrorCode.BlobNotFound || e.ErrorCode == BlobErrorCode.ContainerNotFound)
                        {
                            Logger.LogInformation("Poison monitor data not found for partition {partitionId} attempting to create", partitionId);

                            await UpdatePoisonDataAsync(new PoisonData
                            {
                                PartitionId    = partitionId,
                                ReceiveCount   = 0,
                                SequenceNumber = -1
                            }, cancellationToken).ConfigureAwait(false);

                            response = await blobClient.GetPropertiesAsync(cancellationToken : cancellationToken).ConfigureAwait(false);
                        }
                    }

                    if (response.Value != null)
                    {
                        long?sequenceNumber = default;

                        if (response.Value.Metadata.TryGetValue(SequenceNumber, out var sequence) && long.TryParse(sequence, NumberStyles.Integer, CultureInfo.InvariantCulture, out var sequenceResult))
                        {
                            sequenceNumber = sequenceResult;
                        }

                        int?receiveCount = default;

                        if (response.Value.Metadata.TryGetValue(ReceivedCount, out var received) && int.TryParse(received, NumberStyles.Integer, CultureInfo.InvariantCulture, out var receivedResult))
                        {
                            receiveCount = receivedResult;
                        }

                        data = new PoisonData
                        {
                            PartitionId    = partitionId,
                            ReceiveCount   = receiveCount ?? 0,
                            SequenceNumber = sequenceNumber ?? -1L
                        };
                    }
                }

                _currentData.TryAdd(partitionId, data);
            }

            return(data);
        }
        /// <inheritdoc />
        public async Task <bool> CheckpointStoreExistsAsync()
        {
            var success = false;

            using (_logger.BeginScope("Checkpoint Store Exists"))
            {
                _logger.LogDebug("Check if store exists");

                using (_storagePerformanceSummary.Time())
                {
                    success = await _checkpointStoreContainer.ExistsAsync(_defaultRequestOptions, AzureBlobCommon.DefaultOperationContext).ConfigureAwait(false);
                }

                _logger.LogDebug("Check if store exists result {result}", success);
            }

            return(success);
        }