Beispiel #1
0
        private async Task ProcessBatchesAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                _logger.LogInformation($"Sleeping for {_configuration.BatchFrequencyInMilliseconds} ms.".AddTimestamp());
                await Task.Delay(_configuration.BatchFrequencyInMilliseconds, cancellationToken);

                List <Bet> batch;
                ulong      deliveryTag;
                lock (_betsBatch)
                {
                    batch       = _betsBatch;
                    _betsBatch  = new List <Bet>();
                    deliveryTag = _lastDeliveryTag;
                }

                if (!batch.Any())
                {
                    _logger.LogInformation("No batch to process.".AddTimestamp());
                    continue;
                }

                _logger.LogInformation($"Processing batch of {batch.Count} bets.".AddTimestamp());

                var stakeIds       = batch.Select(b => b.StakeId);
                var betsByStakeIds = batch.GroupBy(b => b.StakeId).ToDictionary(g => g.Key, g => g.Count());

                using (var dbContext = new BetsDbContext(_configuration.ConnectionString))
                    using (var transaction = await dbContext.Database.BeginTransactionAsync(IsolationLevel.RepeatableRead, cancellationToken))
                    {
                        var matches = await dbContext.Matches.Include(m => m.Stakes).Where(m => m.Stakes.Any(s => stakeIds.Contains(s.Id)))
                                      .ToListAsync(cancellationToken);

                        _logger.LogInformation($"Got {matches.Count} matches".AddTimestamp());

                        var newStakes = matches.SelectMany(m => m.Stakes.Where(s => s.IsBettable).Select(s => CalculateNewStake(s, m, betsByStakeIds))).ToList();

                        foreach (var oldStake in matches.SelectMany(m => m.Stakes.Where(s => s.IsBettable)))
                        {
                            oldStake.IsBettable = false;
                        }
                        _logger.LogInformation("Calculated stakes.");
                        dbContext.Stakes.AddRange(newStakes);
                        await dbContext.SaveChangesAsync(cancellationToken);

                        transaction.Commit();
                    }

                EventConsumer.Ack(deliveryTag);
            }
        }
Beispiel #2
0
        public async Task <IActionResult> PutAsync(Bet bet)
        {
            _logger.LogInformation($"Bet:\n{JsonConvert.SerializeObject(bet)}");

            var subject = User.GetSubjectClaim();

            if (bet.UserId != subject)
            {
                _logger.LogError($"Unauthorized claim {subject} for userId = {bet.UserId}.");
                return(Unauthorized());
            }

            var stake = await _betsDbContext.Stakes
                        .Include(s => s.Match)
                        .SingleOrDefaultAsync(s => s.Id == bet.StakeId);

            if (stake == null)
            {
                return(BadRequest($"Specified stake ${bet.StakeId} does not exist."));
            }

            if (stake.Match.IsFinished)
            {
                return(BadRequest($"Match ${stake.MatchId} already finished."));
            }

            var account = await _betsDbContext.Accounts.SingleOrDefaultAsync(a => a.UserId == bet.UserId);

            if (account != null && account.Balance < bet.Amount)
            {
                return(BadRequest($"Insufficient funds."));
            }

            _betsDbContext.Bets.Add(bet);

            _betEventProducer.PublishNewBet(bet);
            await _betsDbContext.SaveChangesAsync();

            return(Ok());
        }
Beispiel #3
0
 public async Task Save()
 {
     await _context.SaveChangesAsync();
 }