定义雪花 64 位整型标识生成器(可生成长度 19 位的长整数标识)。
Inheritance: AbstractClockIdGenerator
Esempio n. 1
0
        public virtual async Task HandleEventAsync(NotificationEventData eventData)
        {
            var notification = NotificationDefinitionManager.Get(eventData.Name);

            var notificationInfo = new NotificationInfo
            {
                Name         = notification.Name,
                CreationTime = eventData.CreationTime,
                Data         = eventData.Data,
                Severity     = eventData.Severity,
                Lifetime     = notification.NotificationLifetime,
                TenantId     = eventData.TenantId,
                Type         = notification.NotificationType
            };

            notificationInfo.SetId(SnowflakeIdGenerator.Create());

            notificationInfo.Data = NotificationDataConverter.Convert(notificationInfo.Data);

            Logger.LogDebug($"Persistent notification {notificationInfo.Name}");

            // 持久化通知
            await NotificationStore.InsertNotificationAsync(notificationInfo);

            var providers = Enumerable
                            .Reverse(NotificationPublishProviderManager.Providers);

            await PublishFromProvidersAsync(providers, eventData.Users, notificationInfo);
        }
        public static string GenerateToken()
        {
            // Attempt to grab operationId for App Insights.
            // If available, assign as correlationToken.
            // If not, generate with Snowflake
            var appInsightOperationKey = System.Diagnostics.Activity.Current.RootId;

            return(!string.IsNullOrEmpty(appInsightOperationKey) ?
                   $"{SnowflakeEnum.Correlation}-{appInsightOperationKey}"
                : SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Correlation));
        }
Esempio n. 3
0
        private void SnowflakeIdGeneratorTask(object workerId)
        {
            int generatorMax = (int)Math.Pow(10, 3);
            SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator((int)workerId, 1);
            var iDGeneratorDictionary        = new Dictionary <string, long>();

            for (int i = 0; i < generatorMax; i++)
            {
                long temp = idGenerator.nextId();
                iDGeneratorDictionary.Add(string.Format("idGenerators-{0}-{1}->{2}", (int)workerId, i + 1, temp), temp);
            }
            lock (lockObj)
            {
                idGeneratorList.AddRange(iDGeneratorDictionary);
            }
        }
        /// <summary>
        ///     Sets the cookie value for the basketId or creates a new ID if null
        /// </summary>
        /// <param name="basketId">
        ///     The <see cref="BasketDto.BasketId">Basket ID</see>.
        ///     If null create a new ID
        /// </param>
        /// <returns>the new The <see cref="BasketDto.BasketId">Basket ID</see></returns>
        public string SetBasketId(string basketId = null)
        {
            //A GUID to hold the basketId.
            if (string.IsNullOrWhiteSpace(basketId))
            {
                // Use SnowflakeIdGenerator to generate BasketId
                basketId = SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Basket);
            }

            var options = new CookieOptions
            {
                Expires  = DateTime.UtcNow.AddDays(7),
                HttpOnly = true
            };

            _httpContextAccessor.HttpContext.Response.Cookies.Append(CookieName, basketId, options);
            return(basketId);
        }
Esempio n. 5
0
 public Order(
     string customerSystemId,
     string checkOutSystemId,
     decimal total,
     string correlationToken)
 //List<OrderDetail> orderDetails)
 {
     OrderSystemId    = SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Order);
     OrderId          = Guid.NewGuid().ToString();
     OrderDate        = DateTime.UtcNow;
     CustomerSystemId = customerSystemId;
     CheckOutSystemId = checkOutSystemId;
     Total            = total;
     CorrelationToken = correlationToken;
     // Set status to Pending
     OrderStatusId = (int)OrderStatusEnum.Pending;
     OrderDetails  = new List <OrderDetail>();
 }
Esempio n. 6
0
        public virtual async Task HandleEventAsync(NotificationEventData eventData)
        {
            // 这样做的话就要注意了
            // 当只有一个消费者订阅时,事件总线会认为消息已经处理,从而发布Ack指令,从消息队列中移除此消息
            // 可能造成通知数据丢失
            var application = Options.Application ?? "Abp";

            if (!string.Equals(application, eventData.Application, StringComparison.InvariantCultureIgnoreCase))
            {
                // 不是当前监听应用的消息不做处理
                return;
            }
            // 如果上面过滤了应用程序,这里可以使用Get方法,否则,最好使用GetOrNull加以判断
            var notification = NotificationDefinitionManager.Get(eventData.Name);

            var notificationInfo = new NotificationInfo
            {
                Name         = notification.Name,
                CreationTime = eventData.CreationTime,
                Data         = eventData.Data,
                Severity     = eventData.Severity,
                Lifetime     = notification.NotificationLifetime,
                TenantId     = eventData.TenantId,
                Type         = notification.NotificationType
            };

            notificationInfo.SetId(SnowflakeIdGenerator.Create());

            // TODO: 可以做成一个接口来序列化消息
            notificationInfo.Data = NotificationDataConverter.Convert(notificationInfo.Data);

            Logger.LogDebug($"Persistent notification {notificationInfo.Name}");

            // 持久化通知
            await NotificationStore.InsertNotificationAsync(notificationInfo);

            var providers = Enumerable
                            .Reverse(NotificationPublishProviderManager.Providers);

            await PublishFromProvidersAsync(providers, eventData.Users, notificationInfo);
        }
        protected async Task <string> PublishNofiterAsync(
            string name,
            NotificationData data,
            IEnumerable <UserIdentifier> users = null,
            Guid?tenantId = null,
            NotificationSeverity severity = NotificationSeverity.Info)
        {
            var eto = new NotificationEto <NotificationData>(data)
            {
                Id           = SnowflakeIdGenerator.Create(),
                TenantId     = tenantId,
                Users        = users?.ToList(),
                Name         = name,
                CreationTime = DateTime.Now,
                Severity     = severity
            };

            await DistributedEventBus.PublishAsync(eto);

            return(eto.Id.ToString());
        }
Esempio n. 8
0
 public void SnowflakeIdGeneratorOne()
 {
     try
     {
         int generatorindex             = 0;
         int generatorMax               = (int)Math.Pow(10, 6);
         SnowflakeIdGenerator idWorker1 = new SnowflakeIdGenerator(1, 1);
         var idGeneratorDictionary      = new Dictionary <string, long>();
         for (int i = generatorindex; i < generatorMax; i++)
         {
             long temp = idWorker1.nextId();
             idGeneratorDictionary.Add(string.Format("{0}->{1}", i + 1, temp), temp);
         }
         Console.WriteLine(JsonConvert.SerializeObject(idGeneratorDictionary, Formatting.Indented));
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.ToString());
         throw;
     }
 }
Esempio n. 9
0
        /// <summary>
        ///     Add single line item to shopping basket
        /// </summary>
        /// <param name="productId">Id of productEntity to add</param>
        /// <param name="correlationToken">Tracks request - can be any value</param>
        /// <param name="basketId">Id of shopping basket</param>
        /// <returns>BasketItemEntity</returns>
        public async Task <BasketEntity> AddItemToBasket(int productId, string correlationToken,
                                                         string basketId)
        {
            //* Materialized View Pattern
            //* Fetch product entity data from a read-only store contained in shopping basket service.
            //* ProductEntity ID is row key in underlying Azure table.
            //* Returns a ProductTableEntity class
            var productTableEntity = await _productRepository.GetItem(ProductPartitionKey, productId.ToString(), correlationToken);

            // Fallback logic
            if (productTableEntity == null)
            {
                // Fallback:
                // If product not available from local read store, fetch it from catalog service by
                // making direct HTTP call to Catalog Service.
                var product = await _restClient.GetAsync <ProductEntity>(ServiceEnum.Catalog, $"api/Catalog/Music/{productId}", correlationToken);

                if (product == null)
                {
                    throw new Exception(
                              $"Cannot add item to shopping basket: ProductEntity #{productId} does not exist for Request {correlationToken}.  Have you created the ProductEntity Read Model for the Shopping BasketEntity microservice?");
                }

                // Transform product into an entity class for table storage
                productTableEntity = new ProductTableEntity
                {
                    // parition key is constant
                    PartitionKey = ProductPartitionKey,
                    // row key is productId
                    RowKey = product.Data.Id.ToString(),

                    Title      = product.Data.Title,
                    Id         = product.Data.Id,
                    GenreName  = product.Data.GenreName,
                    ArtistName = product.Data.ArtistName,
                    Price      = product.Data.Price.ToString()
                };

                // Add product entity tolocal read store, implementing a cache-aside pattern
                await _productRepository.Insert(productTableEntity, correlationToken);

                _logger.LogInformation(
                    $"Added productEntity information for item {productId} for Request {correlationToken} to the read model.");
            }

            BasketEntity basket = null;

            // Does basketID exist?
            if (basketId == "-1")
            {
                basketId = SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Basket);
            }
            else
            {
                basket = await _distributedCacheRepository.GetBasketAsync(basketId, correlationToken, _telemetryClient);
            }

            // Get basket from cache
            if (basket == null)
            {
                // BasketEntity is null, add new single item to it
                basket = new BasketEntity
                {
                    BuyerId          = "2",
                    BasketId         = basketId,
                    CorrelationToken = correlationToken,
                    Items            =
                    {
                        new BasketItemEntity
                        {
                            CorrelationToken = correlationToken,
                            //DateCreated = DateTime.Now,
                            Title     = productTableEntity.Title,
                            UnitPrice = productTableEntity.Price.ToString(),
                            Artist    = productTableEntity.ArtistName,
                            Genre     = productTableEntity.GenreName,
                            Quantity  = 1,
                            ProductId = productId,
                        }
                    }
                };

                basket = await _distributedCacheRepository.UpdateBasketAsync(basket, correlationToken, _telemetryClient);

                _logger.LogInformation($"Created new shopping basket {basketId} and added productEntity {productTableEntity.Title} for Request {correlationToken} ");
            }
            else
            {
                // BasketEntity is not null
                // Determine if the same productEntity has already been added to the basket
                var itemInBasket = basket.Items.FirstOrDefault(x => x.ProductId == Int32.Parse(productTableEntity.RowKey));

                if (itemInBasket == null)
                {
                    // ProductEntity does not exist in basket, add it
                    basket.Items.Add(new BasketItemEntity()
                    {
                        CorrelationToken = correlationToken,
                        //DateCreated = DateTime.Now,
                        Title     = productTableEntity.Title,
                        UnitPrice = productTableEntity.Price.ToString(),
                        Artist    = productTableEntity.ArtistName,
                        Genre     = productTableEntity.GenreName,
                        Quantity  = 1,
                        ProductId = Int32.Parse(productTableEntity.RowKey)
                    });

                    _logger.LogInformation($"Added productEntity Id {productId} to shopping basket {basketId} for request {correlationToken}");
                }
                else
                {
                    // Idempotency write-check
                    // Ensure that update with same correlation token does not already exist.
                    // This could happen if we've already committed the write, but have gotten caught-up in retry logic.
                    if (itemInBasket.CorrelationToken != null && itemInBasket.CorrelationToken == correlationToken)
                    {
                        _logger.LogWarning($"ProductEntity Id {productId} already added to shopping basket {basketId} for Request {correlationToken}");
                        return(basket);
                    }

                    // ProductEntity already exists in basket. Increment its count.
                    basket.Items.FirstOrDefault(x => x.ProductId == Int32.Parse(productTableEntity.RowKey)).Quantity++;

                    _logger.LogInformation($"Added productEntity Id {productId} to existing shopping basket {basketId} for request {correlationToken}");
                }

                basket = await _distributedCacheRepository.UpdateBasketAsync(basket, correlationToken, _telemetryClient);
            }

            return(basket);
        }
Esempio n. 10
0
        /// <summary>
        ///     Invokes check-out process
        /// </summary>
        /// <param name="checkout">User information to create new order</param>
        /// <param name="correlationToken">Tracks request - can be any value</param>
        /// <returns></returns>
        public async Task <CheckoutEntity> Checkout(CheckoutDto checkout, string correlationToken)
        {
            // The shopping basket service is responsible for managing the user's shopping experirence.
            // It does not create or manage with orders.
            // Construct and publish the checkout event so that other services can manage those tasks.

            var total    = 0m;
            var basketId = checkout.BasketId;

            // TODO: Capture UserID from Security Prinicpal
            //var userName = ClaimsPrincipal.Current.Identity.Name ?? "Generic User";
            //https://davidpine.net/blog/principal-architecture-changes/

            // Get user's shopping basket from storage
            var basket = await GetBasketById(basketId, correlationToken);

            // Create the OrderInformationModel
            var orderInformationModel = new OrderInformationModel();

            // Create buyer information object
            var buyer = new OrderInformationModel.BuyerInformation()
            {
                Username   = checkout.Username,
                FirstName  = checkout.FirstName,
                LastName   = checkout.LastName,
                Address    = checkout.Address,
                City       = checkout.City,
                State      = checkout.State,
                PostalCode = checkout.PostalCode,
                Email      = checkout.Email,
                Phone      = checkout.Phone,
            };

            // Create payment information object
            var payment = new OrderInformationModel.PaymentInformation()
            {
                CreditCardNumber = checkout.CreditCardNumber,
                SecurityCode     = checkout.SecurityCode,
                CardholderName   = checkout.CardholderName,
                ExpirationDate   = checkout.ExpirationDate
            };

            // Create event class that will contain shopping basket, buyer, and payment information
            // to create a new order.

            orderInformationModel.BasketId = basketId;
            // Generate system checkoutId using snowflake
            orderInformationModel.CheckoutId = SnowflakeIdGenerator.GenerateId(SnowflakeEnum.Checkout);
            orderInformationModel.Total      = basket.Items.Sum(x => decimal.Parse(x.UnitPrice) * x.Quantity);
            orderInformationModel.Buyer      = buyer;
            orderInformationModel.Payment    = payment;

            foreach (var item in basket.Items)
            {
                orderInformationModel.LineItems.Add(new OrderInformationModel.LineItem()
                {
                    ProductId = item.ProductId,
                    Title     = item.Title,
                    Artist    = item.Artist,
                    Genre     = item.Genre,
                    UnitPrice = item.UnitPrice,
                    Quantity  = item.Quantity
                });
            }

            var checkoutEvent = new CheckOutEvent
            {
                OrderInformationModel = orderInformationModel,
                CorrelationToken      = correlationToken
            };


            _logger.LogInformation($"Check-out operation invoked for shopping basket {basketId} for Request {correlationToken}");

            //************** Publish Event  *************************
            // Publish customer checkout event
            // Ordering subscribes to event and creates order.
            // Once created, Ordering publishes event to have BasketEntity remove basket.
            await _eventBusPublisher.Publish <CheckOutEvent>(checkoutEvent);

            return(new CheckoutEntity
            {
                CheckoutSystemId = checkoutEvent.OrderInformationModel.CheckoutId,
                BuyerEmail = checkoutEvent.OrderInformationModel.Buyer.Email,
                CorrelationId = correlationToken
            });
        }