Example #1
0
        public static async Task Run(
            // Every 4 minutes, between 6:00 PM and 7:59 PM every day.
            [TimerTrigger("0 */4 18-19 * * *")] TimerInfo timer,
            ILogger log)
        {
            var tableService  = new TableService(Environment.GetEnvironmentVariable("AzureWebJobsStorage"));
            var playerFeedRow = (await tableService.GetNextPlayerFeedRows(
                                     rowLimit: 1, minimumTimeSinceLastSync: TimeSpan.FromHours(12)))
                                .SingleOrDefault();

            log.LogInformation($"Queried player feeds table for next feed: {playerFeedRow?.ToString() ?? "N/A"}.");
            if (playerFeedRow == null)
            {
                return;
            }

            var playerRows = await tableService.GetPlayerRows(playerFeedRow);

            log.LogInformation($"Queried players table: {playerRows.Count} rows returned.");

            var scraper = new Scraper(Environment.GetEnvironmentVariable("TransparentUserAgent"));
            var players = await scraper.GetPlayers(playerFeedRow);

            log.LogInformation($"Scraped players: {players.Count} found.");

            var syncResult = new PlayersSyncResult(playerRows, players);

            if (syncResult.DefunctPlayerRows.Any() &&
                !bool.Parse(Environment.GetEnvironmentVariable("AllowDefunctPlayerRows")))
            {
                throw new SyncException("Defunct player rows found, manual intervention required: " +
                                        $"{string.Join(", ", syncResult.DefunctPlayerRows.Select(r => r.ID))}", playerFeedRow.Url);
            }

            log.LogInformation(syncResult.DefunctPlayerRows.Any()
                ? $"Defunct players found: {string.Join(", ", syncResult.DefunctPlayerRows.Select(r => r.ID))}"
                : "No defunct players found.");
            log.LogInformation(syncResult.NewPlayerRows.Any()
                ? $"New players found: {string.Join(", ", syncResult.NewPlayerRows.Select(r => r.ID))}"
                : "No new players found.");
            log.LogInformation(syncResult.UpdatedPlayerRows.Any()
                ? $"Updated players found: {string.Join(", ", syncResult.UpdatedPlayerRows.Select(r => r.ID))}"
                : "No updated players found.");

            if (syncResult.FoundChanges)
            {
                await tableService.UpdatePlayersTable(syncResult);

                log.LogInformation("Players table updated.");
            }

            await tableService.RequeuePlayerFeedRow(playerFeedRow, syncResult.FoundChanges);

            log.LogInformation("Player feed row requeued.");
        }
Example #2
0
        public async Task GetPlayerRows()
        {
            var playerFeeds = Enumerable.Range(1, 50)
                              .Select(i => new PlayerFeed {
                Url = i.ToString()
            })
                              .ToArray();
            var playerRows = await _tableService.GetPlayerRows(playerFeeds[0]);

            Assert.AreEqual(0, playerRows.Count);

            var players = Enumerable.Range(1, 50)
                          .SelectMany(i => Enumerable.Range(1, 5)
                                      .Select(j => new Player
            {
                ID        = $"{i}-{j}",
                Name      = $"{i}-{j}",
                BirthDate = DateTime.UtcNow,
                FeedUrl   = playerFeeds[i - 1].Url,
            }))
                          .ToArray();
            var syncResult = new PlayersSyncResult(Enumerable.Empty <PlayerRow>(), players);
            await _tableService.UpdatePlayersTable(syncResult);

            playerRows = await _tableService.GetPlayerRows(playerFeeds[0]);

            Assert.AreEqual(5, playerRows.Count);
            CollectionAssert.AreEquivalent(
                new[] { "1-1", "1-2", "1-3", "1-4", "1-5" },
                playerRows.Select(r => r.ID).ToArray());

            playerRows = await _tableService.GetPlayerRows(playerFeeds[1]);

            Assert.AreEqual(5, playerRows.Count);
            CollectionAssert.AreEquivalent(
                new[] { "2-1", "2-2", "2-3", "2-4", "2-5" },
                playerRows.Select(r => r.ID).ToArray());

            playerRows = await _tableService.GetPlayerRows(playerFeeds[49]);

            Assert.AreEqual(5, playerRows.Count);
            CollectionAssert.AreEquivalent(
                new[] { "50-1", "50-2", "50-3", "50-4", "50-5" },
                playerRows.Select(r => r.ID).ToArray());

            playerRows = await _tableService.GetPlayerRows(new PlayerFeed { Url = "51" });

            Assert.AreEqual(0, playerRows.Count);
        }
Example #3
0
        public async Task GetNextPlayerRows()
        {
            var players = Enumerable.Range(1, 10)
                          .Select(i => new Player {
                ID = i.ToString(), BirthDate = DateTime.UtcNow
            })
                          .ToArray();
            var syncResult = new PlayersSyncResult(Enumerable.Empty <PlayerRow>(), players);
            await _tableService.UpdatePlayersTable(syncResult);

            var nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();

            Assert.IsTrue(players[0].Matches(nextPlayerRow));

            var nextPlayerRows = await _tableService.GetNextPlayerRows(2, TimeSpan.Zero);

            Assert.IsTrue(players[0].Matches(nextPlayerRows[0]));
            Assert.IsTrue(players[1].Matches(nextPlayerRows[1]));
            Assert.AreEqual(2, nextPlayerRows.Count);

            nextPlayerRows = await _tableService.GetNextPlayerRows(2, TimeSpan.FromDays(1));

            Assert.AreEqual(0, nextPlayerRows.Count);
        }
Example #4
0
 public Task UpdatePlayersTable(PlayersSyncResult syncResult)
 => _playersTable.ExecuteBatchesAsync(syncResult.DefunctPlayerRows.Select(TableOperation.Delete)
                                      .Concat(syncResult.NewPlayerRows.Select(TableOperation.Insert))
                                      .Concat(syncResult.UpdatedPlayerRows.Select(TableOperation.Replace)));
Example #5
0
        public async Task RequeuePlayerRow()
        {
            var playerFeed = new PlayerFeed {
                Url = "1"
            };
            var players = Enumerable.Range(1, 3)
                          .Select(i => new Player
            {
                ID          = i.ToString(),
                FeedUrl     = playerFeed.Url,
                FirstSeason = DateTime.UtcNow.Year - 5,
                LastSeason  = DateTime.UtcNow.Year,
                BirthDate   = DateTime.UtcNow.AddYears(-25)
            })
                          .ToArray();
            var syncResult = new PlayersSyncResult(Enumerable.Empty <PlayerRow>(), players);
            await _tableService.UpdatePlayersTable(syncResult);

            var nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();

            Assert.AreEqual("1", nextPlayerRow.ID);
            Assert.IsNull(nextPlayerRow.LastSyncSeason);
            Assert.IsNull(nextPlayerRow.LastSyncTimeUtc);
            Assert.IsNull(nextPlayerRow.LastSyncWithChangesTimeUtc);
            Assert.AreEqual(nextPlayerRow.FirstSeason, nextPlayerRow.GetNextSyncSeason());

            await _tableService.RequeuePlayerRow(nextPlayerRow, nextPlayerRow.GetNextSyncSeason(), syncFoundChanges : false);

            nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();
            Assert.AreEqual("2", nextPlayerRow.ID);
            Assert.IsNull(nextPlayerRow.LastSyncSeason);
            Assert.IsNull(nextPlayerRow.LastSyncTimeUtc);
            Assert.IsNull(nextPlayerRow.LastSyncWithChangesTimeUtc);
            Assert.AreEqual(nextPlayerRow.FirstSeason, nextPlayerRow.GetNextSyncSeason());

            await _tableService.RequeuePlayerRow(nextPlayerRow, nextPlayerRow.GetNextSyncSeason(), syncFoundChanges : true);

            nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();
            Assert.AreEqual("3", nextPlayerRow.ID);
            Assert.IsNull(nextPlayerRow.LastSyncSeason);
            Assert.IsNull(nextPlayerRow.LastSyncTimeUtc);
            Assert.IsNull(nextPlayerRow.LastSyncWithChangesTimeUtc);
            Assert.AreEqual(nextPlayerRow.FirstSeason, nextPlayerRow.GetNextSyncSeason());

            await _tableService.RequeuePlayerRow(nextPlayerRow, nextPlayerRow.GetNextSyncSeason(), syncFoundChanges : true);

            nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();
            Assert.AreEqual("1", nextPlayerRow.ID);
            Assert.AreEqual(nextPlayerRow.FirstSeason, nextPlayerRow.LastSyncSeason);
            Assert.IsNotNull(nextPlayerRow.LastSyncTimeUtc);
            Assert.IsNull(nextPlayerRow.LastSyncWithChangesTimeUtc);
            Assert.AreEqual(nextPlayerRow.FirstSeason + 1, nextPlayerRow.GetNextSyncSeason());

            await _tableService.RequeuePlayerRow(nextPlayerRow, nextPlayerRow.GetNextSyncSeason(), syncFoundChanges : true);

            nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();
            Assert.AreEqual("2", nextPlayerRow.ID);
            Assert.AreEqual(nextPlayerRow.FirstSeason, nextPlayerRow.LastSyncSeason);
            Assert.IsNotNull(nextPlayerRow.LastSyncTimeUtc);
            Assert.IsNotNull(nextPlayerRow.LastSyncWithChangesTimeUtc);
            Assert.AreEqual(nextPlayerRow.FirstSeason + 1, nextPlayerRow.GetNextSyncSeason());

            await _tableService.RequeuePlayerRow(nextPlayerRow, nextPlayerRow.GetNextSyncSeason(), syncFoundChanges : true);

            var nextPlayerRows = await _tableService.GetNextPlayerRows(3, TimeSpan.Zero);

            CollectionAssert.AreEqual(
                new[] { "3", "1", "2" },
                nextPlayerRows.Select(r => r.ID).ToArray());

            nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();
            Assert.AreEqual("3", nextPlayerRow.ID);

            nextPlayerRow.FirstSeason = 2000;
            nextPlayerRow.LastSeason  = 2010;
            await _tableService.RequeuePlayerRow(nextPlayerRow, 2010, syncFoundChanges : true);

            var playerRows = await _tableService.GetPlayerRows(playerFeed);

            Assert.AreEqual("1", playerRows[0].ID);
            Assert.AreEqual("2", playerRows[1].ID);
            Assert.AreEqual("3", playerRows[2].ID);
            Assert.AreEqual(playerRows[0].FirstSeason + 2, playerRows[0].GetNextSyncSeason());
            Assert.AreEqual(playerRows[1].FirstSeason + 2, playerRows[1].GetNextSyncSeason());
            Assert.AreEqual(playerRows[2].FirstSeason, playerRows[2].GetNextSyncSeason());

            nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();
            Assert.AreEqual("1", nextPlayerRow.ID);

            await _tableService.RequeuePlayerRow(nextPlayerRow, nextPlayerRow.GetNextSyncSeason(), syncFoundChanges : true);

            nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();
            Assert.AreEqual("2", nextPlayerRow.ID);

            await _tableService.RequeuePlayerRow(nextPlayerRow, nextPlayerRow.GetNextSyncSeason(), syncFoundChanges : true);

            nextPlayerRow = (await _tableService.GetNextPlayerRows(1, TimeSpan.Zero)).Single();
            Assert.AreEqual("1", nextPlayerRow.ID); // 3 has been deprioritized.
        }
Example #6
0
        public async Task UpdatePlayersTable()
        {
            var playerFeeds = Enumerable.Range(1, 50)
                              .Select(i => new PlayerFeed {
                Url = i.ToString()
            })
                              .ToArray();
            var players = Enumerable.Range(1, 50)
                          .SelectMany(i => Enumerable.Range(1, 5)
                                      .Select(j => new Player
            {
                ID        = $"{i}-{j}",
                Name      = $"{i}-{j}",
                BirthDate = DateTime.UtcNow,
                FeedUrl   = playerFeeds[i - 1].Url,
            })).ToArray();
            var syncResult = new PlayersSyncResult(Enumerable.Empty <PlayerRow>(), players);
            await _tableService.UpdatePlayersTable(syncResult);

            var playerRowsFeed1 = await _tableService.GetPlayerRows(playerFeeds[0]);

            Assert.AreEqual(5, playerRowsFeed1.Count);

            var updatedPlayersFeed1 = playerRowsFeed1.Select(r => new Player
            {
                ID          = r.ID,
                Name        = r.Name + "-updated",
                FirstSeason = r.FirstSeason + 1,
                LastSeason  = r.LastSeason + 1,
                BirthDate   = r.BirthDate.AddYears(1),
                FeedUrl     = r.FeedUrl,
            }).Concat(Enumerable.Range(6, 5)
                      .Select(i => new Player
            {
                ID        = $"1-{i}",
                Name      = $"1-{i}",
                BirthDate = DateTime.UtcNow,
                FeedUrl   = playerFeeds[0].Url,
            })).ToArray();

            syncResult = new PlayersSyncResult(playerRowsFeed1, updatedPlayersFeed1);
            Assert.AreEqual(0, syncResult.DefunctPlayerRows.Count);
            Assert.AreEqual(5, syncResult.UpdatedPlayerRows.Count);
            Assert.AreEqual(5, syncResult.NewPlayerRows.Count);

            await _tableService.UpdatePlayersTable(syncResult);

            playerRowsFeed1 = await _tableService.GetPlayerRows(playerFeeds[0]);

            Assert.AreEqual(10, playerRowsFeed1.Count);
            Assert.IsTrue(playerRowsFeed1.Zip(updatedPlayersFeed1, (r, p) => r.Matches(p)).All(m => m));

            syncResult = new PlayersSyncResult(playerRowsFeed1, updatedPlayersFeed1);
            Assert.AreEqual(0, syncResult.DefunctPlayerRows.Count);
            Assert.AreEqual(0, syncResult.UpdatedPlayerRows.Count);
            Assert.AreEqual(0, syncResult.NewPlayerRows.Count);

            var playerRowsFeed5 = await _tableService.GetPlayerRows(playerFeeds[4]);

            Assert.AreEqual(5, playerRowsFeed5.Count);

            var updatedPlayersFeed5 = playerRowsFeed5.Select(r => new Player
            {
                ID        = r.ID,
                Name      = r.Name,
                BirthDate = r.BirthDate,
                FeedUrl   = r.FeedUrl,
            }).Concat(Enumerable.Range(6, 1)
                      .Select(i => new Player
            {
                ID        = $"5-{i}",
                Name      = $"5-{i}",
                BirthDate = DateTime.UtcNow,
                FeedUrl   = playerFeeds[4].Url,
            })).ToArray();

            updatedPlayersFeed5[2].Name += "-updated";

            syncResult = new PlayersSyncResult(playerRowsFeed5, updatedPlayersFeed5);
            Assert.AreEqual(0, syncResult.DefunctPlayerRows.Count);
            Assert.AreEqual(1, syncResult.UpdatedPlayerRows.Count);
            Assert.AreEqual(1, syncResult.NewPlayerRows.Count);

            await _tableService.UpdatePlayersTable(syncResult);

            playerRowsFeed1 = await _tableService.GetPlayerRows(playerFeeds[0]);

            playerRowsFeed5 = await _tableService.GetPlayerRows(playerFeeds[4]);

            Assert.AreEqual(10, playerRowsFeed1.Count);
            Assert.IsTrue(playerRowsFeed1.Zip(updatedPlayersFeed1, (r, p) => r.Matches(p)).All(m => m));
            Assert.AreEqual(6, playerRowsFeed5.Count);
            Assert.IsTrue(playerRowsFeed5.Zip(updatedPlayersFeed5, (r, p) => r.Matches(p)).All(m => m));
            Assert.AreEqual(syncResult.UpdatedPlayerRows.Single().RowKey, playerRowsFeed5[2].RowKey);
        }