1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-22 23:00:52 +08:00

Do not forcibly log out user if user retrieval fails with a server error code (#36897)

* Do not forcibly log out user if user retrieval fails with a server error code

This behaviour caused users to get forcibly logged out of the game
during yesterday's redis outage.

From one case where logs were provided
(https://discord.com/channels/188630481301012481/1097318920991559880/1480201862610423933):

- User had repeated timeouts on API requests; consequently, API went
  into failing state
- On one of the login retries `/api/v2/me` returned a 500 with no error
  details (`{"error":"null}` JSON response) which resulted in
  an instant logout as per

  https://github.com/ppy/osu/blob/7263551aa868911a7d9148cf2cb16f9e0325f531/osu.Game/Online/API/APIAccess.cs#L323-L324

This PR intends to only forcibly log the user out if the returned error
code indicates a client error. If it is a server error, the login is
preserved and a normal retry loop proceeds.

This can be tested with a local web instance via following steps:

1. Start `osu-web` and a client instance connected to it.
2. Log in on the client instance.
3. Kill (`^C`) `osu-web`.
4. Trigger a few requests in the client and wait for enough of them to
   fail for the API to change to `Failing` state.
5. Apply

```diff
diff --git a/app/Http/Controllers/UsersController.php b/app/Http/Controllers/UsersController.php
index db34639abf2..392a844882a 100644
--- a/app/Http/Controllers/UsersController.php
+++ b/app/Http/Controllers/UsersController.php
@@ -581,6 +581,8 @@ class UsersController extends Controller
      */
     public function me($mode = null)
     {
+        abort(500);
+
         $user = \Auth::user();
         $currentMode = $mode ?? $user->playmode;

```

6. Start `osu-web` again.
7. On master this will log the user out forcibly. On this PR, the user
   will remain in `Failing` state.
8. Undo patch from step (5) (restarting web is not required).
9. On this PR, the client will be logged back in.

* Update framework

---------

Co-authored-by: Dean Herbert <pe@ppy.sh>
This commit is contained in:
Bartłomiej Dach
2026-03-10 07:12:43 +01:00
committed by GitHub
Unverified
parent 14bde85263
commit caffc7238b
7 changed files with 11 additions and 7 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.303.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.310.0" />
</ItemGroup>
<PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged.
+1 -1
View File
@@ -317,7 +317,7 @@ namespace osu.Game.Online.API
userReq.Failure += ex =>
{
if (ex is APIException)
if (ex is APIException apiException && apiException.StatusCode < HttpStatusCode.InternalServerError)
{
LastLoginError = ex;
log.Add($@"Login failed for username {ProvidedUsername} on user retrieval ({LastLoginError.Message})!");
+5 -1
View File
@@ -2,14 +2,18 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Net;
namespace osu.Game.Online.API
{
public class APIException : InvalidOperationException
{
public APIException(string message, Exception? innerException)
public HttpStatusCode? StatusCode { get; }
public APIException(string message, Exception? innerException, HttpStatusCode? statusCode = null)
: base(message, innerException)
{
StatusCode = statusCode;
}
}
}
+1 -1
View File
@@ -221,7 +221,7 @@ namespace osu.Game.Online.API
// attempt to decode a displayable error string.
var error = JsonConvert.DeserializeObject<DisplayableError>(responseString);
if (error != null)
e = new APIException(error.ErrorMessage, e);
e = new APIException(error.ErrorMessage, e, WebRequest?.ResponseStatusCode);
}
catch
{
+1 -1
View File
@@ -67,7 +67,7 @@ namespace osu.Game.Online.API
// attempt to decode a displayable error string.
var error = JsonConvert.DeserializeObject<OAuthError>(accessTokenRequest.GetResponseString() ?? string.Empty);
if (error != null)
throwableException = new APIException(error.UserDisplayableError, ex);
throwableException = new APIException(error.UserDisplayableError, ex, accessTokenRequest.ResponseStatusCode);
}
catch
{
+1 -1
View File
@@ -35,7 +35,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="20.1.0" />
<PackageReference Include="ppy.osu.Framework" Version="2026.303.0" />
<PackageReference Include="ppy.osu.Framework" Version="2026.310.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2026.305.0" />
<PackageReference Include="Sentry" Version="5.1.1" />
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
+1 -1
View File
@@ -17,6 +17,6 @@
<MtouchInterpreter>-all</MtouchInterpreter>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2026.303.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2026.310.0" />
</ItemGroup>
</Project>