I am having an intermittent issue after being authenticated successfully.
My game hosts a leaderboard per level.(x10 total right now) Users can choose different levels at the front end and view the high scores.
a side affect of this is, when you are bouncing around and viewing different leaderboards, it seems like the connection resets without warning.
No errors coming in the Unity console but...
in xCode(IOS) I get these errors after the issue triggers: (IP's below are obfuscated for post)
2021-07-14 23:39:47.302778-0700 Galactigun[2160:2048393] Connection 22: received failure notification
2021-07-14 23:39:47.348326-0700 Galactigun[2160:2048393] [connection] nw_read_request_report [C22] Receive failed with error "Connection reset by peer"
2021-07-14 23:39:47.348417-0700 Galactigun[2160:2048393] [connection] nw_flow_service_reads [C22.1 47.163.172.32:443 failed channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] No output handler
2021-07-14 23:39:47.348468-0700 Galactigun[2160:2048393] [connection] nw_flow_add_write_request [C22.1 47.163.193.32:443 failed channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] cannot accept write requests
2021-07-14 23:39:47.348502-0700 Galactigun[2160:2048393] [connection] nw_write_request_report [C22] Send failed with error "Socket is not connected"
2021-07-14 23:39:50.026261-0700 Galactigun[2160:2048393] [connection] nw_endpoint_handler_set_adaptive_read_handler [C33.1 47.163.172.32:443 ready channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for read_timeout failed
2021-07-14 23:39:50.026325-0700 Galactigun[2160:2048393] [connection] nw_endpoint_handler_set_adaptive_write_handler [C33.1 47.163.172.32:443 ready channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for write_timeout failed
2021-07-14 23:39:50.577679-0700 Galactigun[2160:2048393] [tcp] tcp_input [C23.1:3] flags=[R.] seq=3693552194, ack=362346775, win=237 state=CLOSE_WAIT rcv_nxt=3693552194, snd_una=362346775
Now, this only really happens when a user is making leaderboard requests at a higher rate than intended, but I would like to understand what is happening.
Do you have any ideas on how I should approach this? I have a feeling it has to do with sending another leaderboard request when the previous request hasn't returned yet.
-Steve
Hi, for a web server the error "Connection reset by peer" could really happen when the website is experiencing a high traffic. If your client code sends many concurrent requests then it could be a problem since it's multiplied by active concurrent users, there's a limit to the number of the concurrent requests that a website can handle.
If you haven't the chance to setup multiple servers in load balancing then you could mitigate it for example by managing a queue for the concurrent requests that you have in your code with a small trick inside a coroutine, something like for example here is a sample coroutine to load all pages of a leaderboard in sequence:
IEnumerator LoadAllScores() { int resultsPerPage = 10; int page = 1; Leaderboard leaderboard = new Leaderboard { code = "L123", timeScope = UnityEngine.SocialPlatforms.TimeScope.AllTime, range = new UnityEngine.SocialPlatforms.Range { from = page, count = resultsPerPage } }; bool downloading; while (page > 0) { downloading = true; leaderboard.LoadScores((bool success) => { if (success) { foreach (Score score in leaderboard.scores) { Debug.Log(string.Format("{0}. {1} {2}", score.rank, score.user.userName, score.formattedValue)); } } if (page < leaderboard.maxRange) { leaderboard.range = new UnityEngine.SocialPlatforms.Range { from = ++page, count = resultsPerPage }; } else { page = 0; } downloading = false; }); while (downloading) yield return new WaitForEndOfFrame(); } }
FRANCESCO CROCETTI @ SKARED CREATIONS
@skaredcreations Yea, this is for sure something I should implement. It's just strange, since the game isn't released yet. It's just a few testers not playing concurrently. So, the server isn't getting overloaded. I don't even see anything in my server logs. I did see that you have a call to cancel a web request. Since my game only displays one leaderboard at a time, I am trying canceling any previous leaderboard calls if the user selects a new leaderboard before the data returns. So far, it seems to help but I am not certain if I am just masking the issue. Is there a way to get an event when the connection is closed? Maybe then, I just reconnect the user?
Appreciate your help btw! I'm just not very versed in PHP/MySql coding/debugging.
-Steve
There isn’t a permanent connection established, the system is built upon calls to web services over HTTP so basically it’s connectionless. That’s why there isn’t any event for closing connection, since there isn’t an “opened connection”.
FRANCESCO CROCETTI @ SKARED CREATIONS
@skaredcreations OK, so all i need is for the initial handshake to complete, then there is no need to reauth for the game session since the token exists, correct? So maybe my code is over complicated causing unnecessary problems for me.
Yes, that's correct. Once that the initial handshake is completed (the phase when the client sends the encryption key to the server to decrypt the next requests), the client is able to make the calls to the web services even if one of them fails for any reason like the one that we're discussing here. In fact you could also implement the code in the callback so that it would retry the LoadScores again if not success in the callback.
FRANCESCO CROCETTI @ SKARED CREATIONS
Thanks, after some more debugging, I've pinpointed it to ILeaderboard.Loadscores .
below is a stripped down version of my load leaderboard call.
"board.LoadScores((bool loaded) =>" gets called and sometimes fails to return with either success or fail.
public static void LoadLeaderboardScores(string leaderboardID,TimeScope timeScope,Action<List<BBScore>,TimeScope> LeaderboardCallback = null) { ILeaderboard board = CombuManager.platform.CreateLeaderboard(); board.id = leaderboardID; board.timeScope = timeScope; board.range = new Range(1, 25); board.LoadScores((bool loaded) => { if (loaded) { } else { Debug.LogError("Failed to Load Top Scores "); } }); }
So, maybe I just need to write my own timeout to capture this case?