Пример #1
0
        public UsageAggregateByBillingCycle GetUsageAggregateByBillingCycle(Guid orderId, Guid billingCycleId, string resourceId)
        {
            UsageAggregateByBillingCycle aggregate = null;

            string partitionKey = string.Format("{0}-{1}", orderId.ToString(), billingCycleId.ToString());
            string rowKey       = resourceId;

            try
            {
                aggregate = (from e in this.aggregateTableServiceContext.CreateQuery <UsageAggregateByBillingCycle>(AggregateUsageTableName)
                             where e.PartitionKey == partitionKey && e.RowKey == rowKey
                             select e).FirstOrDefault();
            }

            catch
            {
                //do nothing, this covers the case when the entity does not exist
                //TODO handle other cases
            }

            return(aggregate);
        }
Пример #2
0
        public bool TrackUsage(UsageEvent usage)
        {
            int          statusCode         = -1;
            BillingCycle currentBillingCyle = this.manager.FetchOrCreateCurrentBillingCycle();

            usage.BillingCycleId = currentBillingCyle.Id;

            //PartitionKey = orderId + billingCycleId
            //RowKey = NewGuid
            usage.PartitionKey = string.Format("{0}-{1}", usage.OrderId.ToString(), usage.BillingCycleId.ToString());
            usage.RowKey       = Guid.NewGuid().ToString();

            //locking to reduce contention for aggregate update if multiple events for same order are coming at the same time
            //this is not foolproff though. TODO - when updates happen from different servers. check what error Azure
            //returns when server1 read, server2 updated, server1 updated
            //based on that tweak the business logic
            lock (lockObject)
            {
                //step1 - fetchORcreate and increment aggregate usage
                UsageAggregateByBillingCycle aggregate = GetUsageAggregateByBillingCycle(usage.OrderId, usage.BillingCycleId, usage.ResourceId);
                bool isNew = false;
                if (aggregate == null)
                {
                    aggregate = new UsageAggregateByBillingCycle {
                        OrderId = usage.OrderId, BillingCycleId = usage.BillingCycleId, ResourceId = usage.ResourceId
                    };
                    aggregate.PartitionKey = string.Format("{0}-{1}", usage.OrderId.ToString(), usage.BillingCycleId.ToString());
                    aggregate.RowKey       = usage.ResourceId;
                    isNew = true;
                }

                aggregate.AmountConsumed += usage.AmountConsumed;

                //step2 - save raw usage
                this.tableContext.AddObject(RawUsageTableName, usage);

                if (isNew)
                {
                    this.aggregateTableServiceContext.AddObject(AggregateUsageTableName, aggregate);
                }

                else
                {
                    this.aggregateTableServiceContext.UpdateObject(aggregate);
                }


                //Now add logic for per user aggregate
                UsageAggregatePerUserByBillingCycle aggregatePerUser = GetUsageAggregatePerUserByBillingCycle(usage.OrderId, usage.BillingCycleId, usage.ResourceId, usage.UserId);
                isNew = false;
                if (aggregatePerUser == null)
                {
                    aggregatePerUser = new UsageAggregatePerUserByBillingCycle {
                        OrderId = usage.OrderId, BillingCycleId = usage.BillingCycleId, ResourceId = usage.ResourceId,
                        UserId  = usage.UserId
                    };
                    aggregatePerUser.PartitionKey = string.Format("{0}-{1}", usage.OrderId.ToString(), usage.BillingCycleId.ToString());
                    aggregatePerUser.RowKey       = string.Format("{0}-{1}", usage.ResourceId, usage.UserId);
                    isNew = true;
                }

                aggregatePerUser.AmountConsumed += usage.AmountConsumed;


                if (isNew)
                {
                    this.aggregatePerUserTableServiceContext.AddObject(AggregatePerUserUsageTableName, aggregatePerUser);
                }

                else
                {
                    this.aggregatePerUserTableServiceContext.UpdateObject(aggregatePerUser);
                }

                //end

                DataServiceResponse response = this.tableContext.SaveChangesWithRetries(SaveChangesOptions.Batch);
                response   = this.aggregateTableServiceContext.SaveChangesWithRetries(SaveChangesOptions.Batch);
                statusCode = response.BatchStatusCode;
            }

            return(statusCode == Http200 || statusCode == 202);
        }