0

I am playing around with Azure functions and wrote my first app in Visual Studio. The function should do the following:

  • Every 5 minutes do the following steps:
  • Call a external API (riot games api) for recent matches that were played.
  • Get even more information from the external API for each of that matches.
  • Convert that information in my DTO (table entity).
  • Store that match in my table storage.

All that steps are done 3 times, since I do that for 3 different players. This is my code without the actual player names and keys:

public static class MatchHistoryUpdater
{
    [FunctionName("MatchHistoryUpdater")]
    public static async Task Run(
        [TimerTrigger("0 */5 * * * *")]TimerInfo myTimer)
    {
        var storageConnectionString = "DefaultEndpointsProtocol=https;AccountName=********;AccountKey=*******==;EndpointSuffix=core.windows.net";
        var account = CloudStorageAccount.Parse(storageConnectionString);
        var serviceClient = account.CreateCloudTableClient();

        var riotClient = new RiotClient(new RiotClientSettings
        {
            ApiKey = "********",
        });

        var accountIds = new List<long> { *****, *****, *****};
        var summonerNames = new List<string> { "*****", "*****", "*****" };

        // valid names, all lower case, no whitespaces, etc.
        var tableNames = new List<string> { "*****", "*****", "*****" };

        var championList = await riotClient.GetStaticChampionsAsync(platformId: PlatformId.EUW1);

        for (var i = 0; i< accountIds.Count; i++)
        {
            var recentMatches = await riotClient.GetMatchListByAccountIdAsync(accountIds[i], platformId: PlatformId.EUW1);
            if (recentMatches.Matches.Count == 0) continue;

            var table = serviceClient.GetTableReference(tableNames[i]);

            foreach(var match in recentMatches.Matches)
            {
                var retrieveOperation = TableOperation.Retrieve<MatchResult>(match.GameId.ToString(), match.Timestamp.ToString());
                var retrievedMatch = table.Execute(retrieveOperation);
                if (retrievedMatch != null) continue;

                var newMatch = await riotClient.GetMatchAsync(match.GameId, PlatformId.EUW1);

                var participantIdentity = newMatch.ParticipantIdentities.Single(x => x.Player.SummonerName == summonerNames[i]);
                var participantId = participantIdentity.ParticipantId;
                var participant = newMatch.Participants.Single(x => x.ParticipantId == participantId);

                var result = "Remake";
                if (participant.Stats.Win) result = "Victory";
                if (!participant.Stats.Win) result = "Defeat";

                var champion = championList.Data.Single(x => x.Value.Id.Equals(participant.ChampionId)).Key;

                var matchResult = new MatchResult
                {
                    PartitionKey = newMatch.GameId.ToString(),
                    RowKey = newMatch.GameCreation.ToString(),
                    Champion = champion,
                    Kills = participant.Stats.Kills,
                    Deaths = participant.Stats.Deaths,
                    Assists = participant.Stats.Assists,
                    Result = result,
                    GameDuration = newMatch.GameDuration.ToString(),
                    TotalDamageDealtToChampions = participant.Stats.TotalDamageDealt,
                    TotalDamageTaken = participant.Stats.TotalDamageTaken,
                    GoldEarned = participant.Stats.GoldEarned,
                    CreepScore = participant.Stats.TotalMinionsKilled + participant.Stats.NeutralMinionsKilled
                };

                var insertOperation = TableOperation.InsertOrReplace(matchResult);
                table.Execute(insertOperation);
            }
        }
    }
}

I start the function app locally and the functions works fine. It succeeds and afterwards I can look in the Azure Storage Explorer and see that all tables were updated just fine.

So now I publish my app to Azure. That works as well. But when I look at my functions invocation log it gives me the following error message:

Exception while executing function: MatchHistoryUpdater
Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: MatchHistoryUpdater ---> Microsoft.WindowsAzure.Storage.StorageException : The remote server returned an error: (400) Bad Request. ---> System.Net.WebException : The remote server returned an error: (400) Bad Request.
   at System.Net.HttpWebRequest.GetResponse()
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand`1 cmd,IRetryPolicy policy,OperationContext operationContext) at c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Executor\Executor.cs : 677 
   End of inner exception
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand`1 cmd,IRetryPolicy policy,OperationContext operationContext) at c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Executor\Executor.cs : 604
   at Microsoft.WindowsAzure.Storage.Table.TableOperation.Execute(CloudTableClient client,CloudTable table,TableRequestOptions requestOptions,OperationContext operationContext) at c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Table\TableOperation.cs : 41
   at Microsoft.WindowsAzure.Storage.Table.CloudTable.Execute(TableOperation operation,TableRequestOptions requestOptions,OperationContext operationContext) at c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Table\CloudTable.cs : 51
   at async LoLChest.MatchHistoryUpdater.Run(TimerInfo myTimer)
   at async Microsoft.Azure.WebJobs.Host.Executors.VoidTaskMethodInvoker`2.InvokeAsync[TReflected,TReturnType](TReflected instance,Object[] arguments)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`2.InvokeAsync[TReflected,TReturnValue](Object instance,Object[] arguments)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.InvokeAsync(IFunc…

I already thought that this might be because of the lines retrieving the entity because of some kind of rate limit and commented those lines:

var retrieveOperation = TableOperation.Retrieve<MatchResult>(match.GameId.ToString(), match.Timestamp.ToString());
                    var retrievedMatch = table.Execute(retrieveOperation);
                    if (retrievedMatch != null) continue;

But anyway: I get the same error that way.

So now I am stuck. Does anybody know why it might behave differently local than on azure?

Thanks in advance!

Mikhail Shilkov
  • 34,128
  • 3
  • 68
  • 107
selmaohneh
  • 553
  • 2
  • 17
  • Check this answer. It might have something to do with DateTime min values. https://stackoverflow.com/questions/14859405/azure-table-storage-returns-400-bad-request StorageException.RequestInformation.ExtendedInformation might have additional information. Have you tried remote debugging into your live execution? Easily possible with VS – alwayslearning Dec 09 '17 at 09:42
  • In the table all my times are stored as strings. I only parse them to a DateTime when actually doing some logic. That's why I think that this is not the problem, right? – selmaohneh Dec 09 '17 at 10:17
  • check the comments on the answer - https://stackoverflow.com/a/14866888/233697 There are quite a few other reasons why you might get the error. Also trying debugging and getting to the actual RequestInformation.ExtendedInformation property. It might throw some more light – alwayslearning Dec 09 '17 at 10:20
  • Are you sure your function is reading a valid Storage Account key? That's another reason for a 400 Bad Request. – evilSnobu Dec 09 '17 at 17:44
  • Is your table using Premium storage or standard storage? – Baskar Rao Dec 10 '17 at 00:03
  • It's using standard. The connection String is correct, since it is working locally. Im gonna debug it remotely. – selmaohneh Dec 10 '17 at 00:18
  • There is an issue which is already raised with functions team.https://github.com/Azure-Samples/azure-cosmos-db-table-dotnet-getting-started/issues/5 – Baskar Rao Dec 10 '17 at 03:25

0 Answers0