Cloud Code Module doesn't work with Cloud Save

Hey there.

I’m trying to implement an automated tournament system for my game, but Cloud code is just behaving in very whack ways when I try to generate brackets once players have registered the tournament.

This is my Cloud Code Endpoint:

[CloudCodeFunction("StartTournament")]
    public async Task<TournamentDTO> StartTournament(IExecutionContext context, IGameApiClient gameApiClient, string code)
    {
        _logger.LogInformation("Starting tournament: "+ code);
        TournamentDTO tournamentDto = await GetTournamentByCode(context, gameApiClient, code);
        _logger.LogTrace("Here");
        tournamentDto.State = TournamentDTO.TournamentState.ONGOING;
      
        if (tournamentDto.TournamentType != TournamentDTO.TournamentMode.GOLDEN_BOOT)
        {
            if (tournamentDto.TournamentType != TournamentDTO.TournamentMode.CUSTOM)
            {
                _logger.LogDebug("Generating brackets: "+ code);
                tournamentDto.Brackets.Children = GenerateBrackets(tournamentDto);
            }
        }

        tournamentDto.Brackets.Start(_logger, tournamentDto);

        return UpdateTournament(context, gameApiClient, tournamentDto);
    }

private async Task<TournamentDTO> GetTournamentByCode(IExecutionContext context, IGameApiClient gameApiClient, string code)
{
    _logger.LogTrace("GetTournamentByCode");
    ApiResponse<GetItemsResponse> apiResponse = await gameApiClient.CloudSaveData.GetCustomItemsAsync(context, context.ServiceToken, context.ProjectId, "Tournament"+code);
    GetItemsResponse getItemsResponse = apiResponse.Data;
    TournamentDTO tournamentDto = JsonConvert.DeserializeObject<TournamentDTO>(getItemsResponse.Results[0].Value.ToString());
    _logger.LogDebug("Tournament Found: "+ LogifyTouranamentDto(tournamentDto));
    return tournamentDto;
}

It prints the first log (Starting Tournameng + code), but then I get an error 500 when calling GetTournamentByCode without reaching any of the logs inside the method. Mind you, I’m calling this method inside other ClodeCode functions (create tournaments and addPlayers) and it works perfectly, it is only on this very specific method that it fails, although I’m treating the data the same way in those three methods. the stack trace really says nothing, in fact, if anything, it’s even more misleading:

HttpException`1: (500) HTTP/1.1 500 Internal Server Error
  at Unity.Services.CloudCode.Internal.Http.ResponseHandler.HandleAsyncResponse (Unity.Services.CloudCode.Internal.Http.HttpClientResponse response, System.Collections.Generic.Dictionary`2[TKey,TValue] statusCodeToTypeMap) [0x00089] in .\Library\PackageCache\com.unity.services.cloudcode@2.5.1\Runtime\com.unity.services.cloudcode.internal\Http\ResponseHandler.cs:122
  at Unity.Services.CloudCode.Internal.Http.ResponseHandler.HandleAsyncResponse[T] (Unity.Services.CloudCode.Internal.Http.HttpClientResponse response, System.Collections.Generic.Dictionary`2[TKey,TValue] statusCodeToTypeMap) [0x00001] in .\Library\PackageCache\com.unity.services.cloudcode@2.5.1\Runtime\com.unity.services.cloudcode.internal\Http\ResponseHandler.cs:226
  at Unity.Services.CloudCode.Internal.Apis.CloudCode.CloudCodeApiClient.RunModuleAsync (Unity.Services.CloudCode.Internal.CloudCode.RunModuleRequest request, Unity.Services.CloudCode.Internal.Configuration operationConfiguration) [0x001fd] in .\Library\PackageCache\com.unity.services.cloudcode@2.5.1\Runtime\com.unity.services.cloudcode.internal\Apis\CloudCodeApi.cs:137
  at Unity.Services.CloudCode.CloudCodeInternal.GetModuleResponseAsync (System.String module, System.String function, System.Collections.Generic.Dictionary`2[TKey,TValue] args) [0x00082] in .\Library\PackageCache\com.unity.services.cloudcode@2.5.1\Runtime\CloudCode.cs:243
  at Unity.Services.CloudCode.CloudCodeInternal.GetRunModuleScriptResponse (System.String module, System.String function, System.Collections.Generic.Dictionary`2[TKey,TValue] args) [0x00047] in .\Library\PackageCache\com.unity.services.cloudcode@2.5.1\Runtime\CloudCode.cs:137
Rethrow as CloudCodeException: ServiceUnavailable
(500) HTTP/1.1 500 Internal Server Error
Error
An unknown server error occurred

The Cloud Code Log console only shows the logs that I added, and shows nothign about the error at hand, I extracted these logs from my Player.log

I’ve tried debugging this code in the most ridiculous way possible (moving the _logger.LogTrace(“Here”); line by line and even inside the utility method to see what’s even going on). But the result is always the same. _logger.LogTrace(“Here”); and _logger.LogTrace(“GetTournamentByCode”); are never called. I also tried reviewing the quotas for CloudSave API andI’m not exceeding the 600 calls per minute that it allows for these endpoints.

Now if I remove the variable assignation on line 5, and leave the line just as
await GetTournamentByCode(context, gameApiClient, code); and then instantiate a dummy TournamentDTO, it works.

This has been an incredibly frustrating issue and a total road block for this very core funcitonality, which my community anticipates greatly. I’m tryign my best not to vent here, but I’m one month away from release and you have to concede that CloudCode is not making any efforts in communicating properly what’s the issue.

I’m flaging this as a Bug because, even if this is an error from my side, something has to be done about this logging for the product to actually be usable.

Any idea what might be going wrong on this endpoint?

Hi @ANLevant ,

I’ve managed to find the logs for your project based on the module’s function name and can see that the C# module resource was failing to return a response hence the unexpected 500 error. I was able to find some further stack trace logs which I’ve shared below which I hope are useful. From the log output I suspect the code is hitting an infinite loop somewhere in the GenerateBrackets logic which is preventing the C# module resource from shipping the logs, we’ll have to do some further testing on our side to verify thats the case and see about how we handle these types of exceptions better.

(Please note I’ve obfuscated the module name in the output)

2024-04-08 21:28:45.718
Stack overflow.
2024-04-08 21:28:45.724
Repeat 24409 times:
2024-04-08 21:28:45.724
--------------------------------

>>> at xxxxxModule.TournamentManager.CreateTournamentStructure(xxxxModule.TournamentNode) <<<

2024-04-08 21:28:45.724
--------------------------------
2024-04-08 21:28:45.724
   at xxxxModule.TournamentManager.GenerateBrackets(xxxxModule.TournamentDTO)
2024-04-08 21:28:45.724
   at xxxxgModule.TournamentManager+<StartTournament>d__8.MoveNext()
2024-04-08 21:28:45.724
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
2024-04-08 21:28:45.724
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[xxxxxModule.TournamentManager+<StartTournament>d__8, xxxxxModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext(System.Threading.Thread)
2024-04-08 21:28:45.724
   at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Runtime.CompilerServices.IAsyncStateMachineBox, Boolean)
2024-04-08 21:28:45.724
   at System.Threading.Tasks.Task.RunContinuations(System.Object)
2024-04-08 21:28:45.724
   at xxxxxModule.TournamentManager+<GetTournamentByCode>d__13.MoveNext()
...

In the mean time, my best suggestion would be to create a unit test for the function to see if that highlights the issue Create a unit test

1 Like

Thank you very very veeeery much. This is exactly what I neeeded. Perhaps the break condition of the method is never being hit. Iwill investigate the issue with the logs. I’m new to Cloud Code Services, I’ve mostly coded backend solutions with Java and Amazon / Kubernetes. Knowing that I can implement Unit Tests is indeed a very good thing. Thanks again!

1 Like