private async Task <bool> PushBucketAsync(BillingUsageBucket bucket, CancellationToken cancellationToken) { try { var records = await bucket.GetRecordsAsync(cancellationToken); if (records == null || records.Count <= 0) { BillingEventSource.Current.Warning(BillingEventSource.EmptyTrackingId, this, nameof(this.PushBucketAsync), OperationStates.Dropped, $"Bucket '{bucket.BucketKey}' has no records."); return(true); } var batchId = Guid.NewGuid(); var pushAny = 0; // Push to table Func <IEnumerable <ResourceUsageRecord>, Guid, Task> pushBatchFunc = async(batch, id) => { bool succeed = await this.PushUsageBatchAsync(batch, id, cancellationToken); if (succeed) { Interlocked.Exchange(ref pushAny, 1); } }; await this.ParallelPushAsync(records, batchId, pushBatchFunc); if (pushAny > 0) { // Notify to queue await NotifyPushAsync(batchId, cancellationToken); await bucket.ClearAsync(); } return(pushAny > 0); } catch (Exception ex) { BillingEventSource.Current.ErrorException(BillingEventSource.EmptyTrackingId, this, nameof(this.PushBucketAsync), OperationStates.Failed, string.Empty, ex); return(false); } }
private Task <BillingUsageBucket> GetNextBucketInStateAsync(string fromBucket, bool exclude, List <BillingUsageBucketState> states, CancellationToken cancellationToken) { // If fromBucket is null, search from begining var skip = !string.IsNullOrEmpty(fromBucket); BillingUsageBucket bucket = null; this.bucketStateLock.EnterReadLock(); try { // Loop to 2 * count of bucket size, to start from fromBucket for (var i = 0; i < this.buckets.Count * 2; i++) { var current = this.buckets.Values.ElementAt(i % this.buckets.Count); if (skip && current.BucketKey == fromBucket) { skip = false; if (exclude) { continue; } } if (skip) { continue; } if (states.Contains(current.State)) { bucket = current; break; } } } finally { this.bucketStateLock.ExitReadLock(); } return(Task.FromResult(bucket)); }