diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58443bd..203f29a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,13 +8,13 @@ on: jobs: unit-tests: - runs-on: ubuntu-latest - container: node:10.18-jessie services: redis: image: redis + ports: + - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 10s @@ -22,16 +22,15 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v2 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + - name: Checkout + uses: actions/checkout@v4 + - name: Install .NET 8.0.x + uses: actions/setup-dotnet@v4 with: - dotnet-version: "6.0.x" + dotnet-version: "8.0.x" - name: Install dependencies run: dotnet restore - name: Build run: dotnet build --no-restore - name: Test - env: - REDIS_HOST: redis run: dotnet test --no-restore --verbosity normal diff --git a/.github/workflows/pack.yml b/.github/workflows/pack.yml index bf0595d..41323d4 100644 --- a/.github/workflows/pack.yml +++ b/.github/workflows/pack.yml @@ -9,13 +9,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + - name: Checkout + uses: actions/checkout@v4 + - name: Install .NET 8.0.x + uses: actions/setup-dotnet@v4 with: - dotnet-version: "6.0.x" - source-url: https://nuget.pkg.github.com/ppy/index.json + dotnet-version: "8.0.x" env: NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Get the version diff --git a/osu.Server.QueueProcessor.Tests/BatchProcessorTests.cs b/osu.Server.QueueProcessor.Tests/BatchProcessorTests.cs index 5c5c599..d777fd8 100644 --- a/osu.Server.QueueProcessor.Tests/BatchProcessorTests.cs +++ b/osu.Server.QueueProcessor.Tests/BatchProcessorTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -88,6 +89,7 @@ public void SendThenReceive_Multiple() /// If the processor is cancelled mid-operation, every item should either be processed or still in the queue. /// [Fact] + [SuppressMessage("Usage", "xUnit1031:Do not use blocking task operations in test method")] // For simplicity. public void EnsureCancellingDoesNotLoseItems() { var inFlightObjects = new List(); diff --git a/osu.Server.QueueProcessor.Tests/InputOnlyQueueTests.cs b/osu.Server.QueueProcessor.Tests/InputOnlyQueueTests.cs index 7427506..f47a1bd 100644 --- a/osu.Server.QueueProcessor.Tests/InputOnlyQueueTests.cs +++ b/osu.Server.QueueProcessor.Tests/InputOnlyQueueTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -106,6 +107,7 @@ public void SendThenReceive_MultipleUsingSingleCall() /// If the processor is cancelled mid-operation, every item should either be processed or still in the queue. /// [Fact] + [SuppressMessage("Usage", "xUnit1031:Do not use blocking task operations in test method")] // For simplicity. public void EnsureCancellingDoesNotLoseItems() { var inFlightObjects = new List(); diff --git a/osu.Server.QueueProcessor.Tests/osu.Server.QueueProcessor.Tests.csproj b/osu.Server.QueueProcessor.Tests/osu.Server.QueueProcessor.Tests.csproj index c0b9078..ed8af6b 100644 --- a/osu.Server.QueueProcessor.Tests/osu.Server.QueueProcessor.Tests.csproj +++ b/osu.Server.QueueProcessor.Tests/osu.Server.QueueProcessor.Tests.csproj @@ -1,19 +1,19 @@ - net6.0 + net8.0 enable false - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/osu.Server.QueueProcessor.sln.DotSettings b/osu.Server.QueueProcessor.sln.DotSettings index c8c5d67..1e04d7d 100644 --- a/osu.Server.QueueProcessor.sln.DotSettings +++ b/osu.Server.QueueProcessor.sln.DotSettings @@ -769,9 +769,19 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Type parameters"><ElementKinds><Kind Name="TYPE_PARAMETER" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"><ExtraRule Prefix="_" Suffix="" Style="aaBb" /></Policy></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local functions"><ElementKinds><Kind Name="LOCAL_FUNCTION" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Enum members"><ElementKinds><Kind Name="ENUM_MEMBER" /></ElementKinds></Descriptor><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local constants"><ElementKinds><Kind Name="LOCAL_CONSTANT" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> @@ -815,6 +825,8 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True +||||||| 848eaa8 True True True @@ -836,6 +848,7 @@ See the LICENCE file in the repository root for full licence text. True True True + True TestFolder True True diff --git a/osu.Server.QueueProcessor/ConnectionMultiplexerExtensions.cs b/osu.Server.QueueProcessor/ConnectionMultiplexerExtensions.cs index 6a94597..a859fda 100644 --- a/osu.Server.QueueProcessor/ConnectionMultiplexerExtensions.cs +++ b/osu.Server.QueueProcessor/ConnectionMultiplexerExtensions.cs @@ -34,7 +34,7 @@ public static void ClearCurrentSchema(this ConnectionMultiplexer connection) /// /// Get all active schemas (including past or future). /// - public static string[] GetActiveSchemas(this ConnectionMultiplexer connection) + public static string?[] GetActiveSchemas(this ConnectionMultiplexer connection) { return connection.GetDatabase().SetMembers(allActiveSchemasKey).ToStringArray(); } @@ -44,7 +44,7 @@ public static string[] GetActiveSchemas(this ConnectionMultiplexer connection) /// public static string GetCurrentSchema(this ConnectionMultiplexer connection) { - return connection.GetDatabase().StringGet(mainSchemaKey).ToString() ?? string.Empty; + return connection.GetDatabase().StringGet(mainSchemaKey).ToString(); } /// diff --git a/osu.Server.QueueProcessor/QueueProcessor.cs b/osu.Server.QueueProcessor/QueueProcessor.cs index 7e5ca15..8fd2df0 100644 --- a/osu.Server.QueueProcessor/QueueProcessor.cs +++ b/osu.Server.QueueProcessor/QueueProcessor.cs @@ -107,6 +107,7 @@ public void Run(CancellationToken cancellation = default) var redisItems = database.ListRightPop(QueueName, config.BatchSize); + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract (https://github.com/StackExchange/StackExchange.Redis/issues/2697) // queue doesn't exist. if (redisItems == null) { @@ -118,7 +119,7 @@ public void Run(CancellationToken cancellation = default) // null or empty check is required for redis 6.x. 7.x reports `null` instead. foreach (var redisItem in redisItems.Where(i => !i.IsNullOrEmpty)) - items.Add(JsonConvert.DeserializeObject(redisItem) ?? throw new InvalidOperationException("Dequeued item could not be deserialised.")); + items.Add(JsonConvert.DeserializeObject(redisItem!) ?? throw new InvalidOperationException("Dequeued item could not be deserialised.")); if (items.Count == 0) { @@ -190,7 +191,7 @@ public void Run(CancellationToken cancellation = default) private void setupSentry(SentryOptions options) { - options.Dsn = Environment.GetEnvironmentVariable("SENTRY_DSN"); + options.Dsn = Environment.GetEnvironmentVariable("SENTRY_DSN") ?? string.Empty; options.DefaultTags["queue"] = QueueName; } @@ -253,7 +254,7 @@ public long GetQueueSize() => /// The type of message to be published. public void PublishMessage(string channelName, TMessage message) { - getRedisDatabase().Publish(channelName, JsonConvert.SerializeObject(message)); + getRedisDatabase().Publish(new RedisChannel(channelName, RedisChannel.PatternMode.Auto), JsonConvert.SerializeObject(message)); DogStatsd.Increment("messages_published", tags: new[] { $"channel:{channelName}", $"type:{typeof(TMessage).FullName}" }); } diff --git a/osu.Server.QueueProcessor/osu.Server.QueueProcessor.csproj b/osu.Server.QueueProcessor/osu.Server.QueueProcessor.csproj index ce70aff..7a435a7 100644 --- a/osu.Server.QueueProcessor/osu.Server.QueueProcessor.csproj +++ b/osu.Server.QueueProcessor/osu.Server.QueueProcessor.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 OsuQueueProcessor ppy.osu.Server.OsuQueueProcessor Dean Herbert @@ -11,12 +11,12 @@ - - - - - - + + + + + +