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!