From e241852e8a5626aeb82559efc4cd838ad0ff703a Mon Sep 17 00:00:00 2001 From: james gilles Date: Tue, 11 Feb 2025 13:21:06 -0500 Subject: [PATCH] Emit Event.UnknownTransaction rather than throwing on unknown reducer (#244) ## Description of Changes as described ## API no breaks ## Requires SpacetimeDB PRs https://github.com/clockworklabs/SpacetimeDB/pull/2241 ## Testsuite SpacetimeDB branch name: jgilles/unknown_reducer ## Testing see SpacetimeDB PR --- examples~/quickstart/client/Program.cs | 9 --- .../module_bindings/SpacetimeDBClient.g.cs | 4 - .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll | Bin 58368 -> 58368 bytes .../SpacetimeDB.BSATN.Runtime.dll | Bin 65024 -> 65024 bytes src/SpacetimeDBClient.cs | 47 ++++------- ...p_dumpName=LegacySubscribeAll.verified.txt | 65 ++++++++++------ ...ump_dumpName=SubscribeApplied.verified.txt | 73 +++++++++++------- tests~/SnapshotTests.cs | 12 +-- tools~/update-against-stdb.sh | 21 +++++ unity-tests~ | 2 +- 10 files changed, 128 insertions(+), 105 deletions(-) create mode 100644 tools~/update-against-stdb.sh diff --git a/examples~/quickstart/client/Program.cs b/examples~/quickstart/client/Program.cs index 7c4a891..fc48da6 100644 --- a/examples~/quickstart/client/Program.cs +++ b/examples~/quickstart/client/Program.cs @@ -37,10 +37,6 @@ void Main() conn.Reducers.OnSetName += Reducer_OnSetNameEvent; conn.Reducers.OnSendMessage += Reducer_OnSendMessageEvent; -#pragma warning disable CS0612 // Using obsolete API - conn.onUnhandledReducerError += onUnhandledReducerError; -#pragma warning restore CS0612 // Using obsolete API - // declare a threadsafe cancel token to cancel the process loop var cancellationTokenSource = new CancellationTokenSource(); @@ -176,11 +172,6 @@ void OnSubscriptionApplied(SubscriptionEventContext ctx) PrintMessagesInOrder(ctx.Db); } -void onUnhandledReducerError(ReducerEvent reducerEvent) -{ - Console.WriteLine($"Unhandled reducer error in {reducerEvent.Reducer}: {reducerEvent.Status}"); -} - void ProcessThread(DbConnection conn, CancellationToken ct) { try diff --git a/examples~/quickstart/client/module_bindings/SpacetimeDBClient.g.cs b/examples~/quickstart/client/module_bindings/SpacetimeDBClient.g.cs index 97c69fa..4dafe25 100644 --- a/examples~/quickstart/client/module_bindings/SpacetimeDBClient.g.cs +++ b/examples~/quickstart/client/module_bindings/SpacetimeDBClient.g.cs @@ -100,8 +100,6 @@ internal SubscriptionEventContext(DbConnection conn) public abstract partial class Reducer { private Reducer() { } - - public sealed class StdbNone : Reducer { } } public sealed class DbConnection : DbConnectionBase @@ -125,7 +123,6 @@ protected override Reducer ToReducer(TransactionUpdate update) "identity_disconnected" => BSATNHelpers.Decode(encodedArgs), "send_message" => BSATNHelpers.Decode(encodedArgs), "set_name" => BSATNHelpers.Decode(encodedArgs), - "" or "" => new Reducer.StdbNone(), var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } @@ -151,7 +148,6 @@ protected override bool Dispatch(IReducerEventContext context, Reducer reducer) Reducer.IdentityDisconnected args => Reducers.InvokeIdentityDisconnected(eventContext, args), Reducer.SendMessage args => Reducers.InvokeSendMessage(eventContext, args), Reducer.SetName args => Reducers.InvokeSetName(eventContext, args), - Reducer.StdbNone => true, _ => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc4/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/1.0.0-rc4/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll index f6ccf968de6d53ba197a6064a52c8f4cc08d302a..2e6a26a457774193105fba1fcd45b10b8cfb5fa8 100755 GIT binary patch delta 2337 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 diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc4/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/1.0.0-rc4/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll index 6a8aa95e2a63b6b6ff325891cb23a250b1a03e87..dcc7f4ec6b9eec1519b250be82fdddf2c6a1fc9a 100755 GIT binary patch literal 65024 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 Qmpl3rub+SZ-$~$q0sRM private UintAllocator queryIdAllocator; - /// - /// Invoked when a reducer is returned with an error and has no client-side handler. - /// - [Obsolete] - public event Action>? onUnhandledReducerError; - public readonly ConnectionId ConnectionId = ConnectionId.Random(); public Identity? Identity { get; private set; } @@ -617,9 +611,11 @@ PreProcessedMessage PreProcessMessage(UnprocessedMessage unprocessed) transactionUpdate.EnergyQuantaUsed.Quanta, ToReducer(transactionUpdate)); } - catch (Exception e) + catch (Exception) { - Log.Exception(e); + // Failing to parse the ReducerEvent is fine, it just means we should + // call downstream stuff with an UnknownTransaction. + // See OnProcessMessageComplete. } if (transactionUpdate.Status is UpdateStatus.Committed(var committed)) @@ -809,6 +805,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed) var eventContext = MakeSubscriptionEventContext(); var legacyEventContext = ToEventContext(new Event.SubscribeApplied()); OnMessageProcessCompleteUpdate(legacyEventContext, dbOps); + if (legacySubscriptions.TryGetValue(initialSubscription.RequestId, out var subscription)) { try @@ -929,36 +926,20 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed) } } - if (processed.reducerEvent is not { } reducerEvent) - { - // If we are here, an error about unknown reducer should have already been logged, so nothing to do. - break; - } - var eventContext = ToReducerEventContext(reducerEvent); - var legacyEventContext = ToEventContext(new Event.Reducer(reducerEvent)); - OnMessageProcessCompleteUpdate(legacyEventContext, dbOps); - var reducerFound = false; - try + if (processed.reducerEvent is { } reducerEvent) { - reducerFound = Dispatch(eventContext, reducerEvent.Reducer); + var legacyEventContext = ToEventContext(new Event.Reducer(reducerEvent)); + OnMessageProcessCompleteUpdate(legacyEventContext, dbOps); + var eventContext = ToReducerEventContext(reducerEvent); + Dispatch(eventContext, reducerEvent.Reducer); + // don't invoke OnUnhandledReducerError, that's [Obsolete]. } - catch (Exception e) - { - Log.Exception(e); - } - - if (!reducerFound && transactionUpdate.Status is UpdateStatus.Failed(var failed)) + else { - try - { - onUnhandledReducerError?.Invoke(reducerEvent); - } - catch (Exception e) - { - Log.Exception(e); - } + var legacyEventContext = ToEventContext(new Event.UnknownTransaction()); + OnMessageProcessCompleteUpdate(legacyEventContext, dbOps); } break; } diff --git a/tests~/SnapshotTests.VerifySampleDump_dumpName=LegacySubscribeAll.verified.txt b/tests~/SnapshotTests.VerifySampleDump_dumpName=LegacySubscribeAll.verified.txt index 13d6ba3..66a6b39 100644 --- a/tests~/SnapshotTests.VerifySampleDump_dumpName=LegacySubscribeAll.verified.txt +++ b/tests~/SnapshotTests.VerifySampleDump_dumpName=LegacySubscribeAll.verified.txt @@ -19,7 +19,20 @@ online: true } }, - LogException: Unknown reducer unknown-reducer (Parameter 'Reducer'), + OnInsertUser: { + eventContext: { + Event: { + $type: Event.UnknownTransaction + }, + Db: {Scrubbed}, + Reducers: {Scrubbed}, + SetReducerFlags: {} + }, + user: { + identity: Identity_2, + online: true + } + }, OnInsertUser: { eventContext: { Event: { @@ -29,7 +42,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -42,7 +55,7 @@ SetReducerFlags: {} }, user: { - identity: Identity_2, + identity: Identity_3, online: true } }, @@ -98,7 +111,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -113,7 +126,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -127,7 +140,7 @@ SetReducerFlags: {} }, message: { - sender: Identity_2, + sender: Identity_3, sent: 1718487775346381, text: Hello, A! } @@ -138,7 +151,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -152,7 +165,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -167,7 +180,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -181,11 +194,11 @@ SetReducerFlags: {} }, oldUser: { - identity: Identity_2, + identity: Identity_3, online: true }, newUser: { - identity: Identity_2, + identity: Identity_3, name: B, online: true } @@ -196,7 +209,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -210,7 +223,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -264,7 +277,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -279,7 +292,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -293,7 +306,7 @@ SetReducerFlags: {} }, message: { - sender: Identity_2, + sender: Identity_3, sent: 1718487787645364, text: Goodbye! } @@ -304,7 +317,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -318,7 +331,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -333,7 +346,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -346,12 +359,12 @@ SetReducerFlags: {} }, oldUser: { - identity: Identity_2, + identity: Identity_3, name: B, online: true }, newUser: { - identity: Identity_2, + identity: Identity_3, name: B, online: false } @@ -404,7 +417,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -420,13 +433,17 @@ }, { identity: Identity_2, + online: true + }, + { + identity: Identity_3, name: B, online: false } ], Message: [ { - sender: Identity_2, + sender: Identity_3, sent: 1718487775346381, text: Hello, A! }, @@ -436,7 +453,7 @@ text: Hello, B! }, { - sender: Identity_2, + sender: Identity_3, sent: 1718487787645364, text: Goodbye! }, diff --git a/tests~/SnapshotTests.VerifySampleDump_dumpName=SubscribeApplied.verified.txt b/tests~/SnapshotTests.VerifySampleDump_dumpName=SubscribeApplied.verified.txt index 5dc1bac..353c6ad 100644 --- a/tests~/SnapshotTests.VerifySampleDump_dumpName=SubscribeApplied.verified.txt +++ b/tests~/SnapshotTests.VerifySampleDump_dumpName=SubscribeApplied.verified.txt @@ -19,7 +19,20 @@ online: true } }, - LogException: Unknown reducer unknown-reducer (Parameter 'Reducer'), + OnInsertUser: { + eventContext: { + Event: { + $type: Event.UnknownTransaction + }, + Db: {Scrubbed}, + Reducers: {Scrubbed}, + SetReducerFlags: {} + }, + user: { + identity: Identity_2, + online: true + } + }, OnInsertUser: { eventContext: { Event: { @@ -29,7 +42,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -42,7 +55,7 @@ SetReducerFlags: {} }, user: { - identity: Identity_2, + identity: Identity_3, online: true } }, @@ -98,7 +111,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -113,7 +126,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -127,7 +140,7 @@ SetReducerFlags: {} }, message: { - sender: Identity_2, + sender: Identity_3, sent: 1718487775346381, text: Hello, A! } @@ -138,7 +151,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -152,7 +165,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -167,7 +180,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -181,11 +194,11 @@ SetReducerFlags: {} }, oldUser: { - identity: Identity_2, + identity: Identity_3, online: true }, newUser: { - identity: Identity_2, + identity: Identity_3, name: B, online: true } @@ -196,7 +209,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -210,7 +223,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -264,7 +277,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -279,7 +292,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -293,7 +306,7 @@ SetReducerFlags: {} }, message: { - sender: Identity_2, + sender: Identity_3, sent: 1718487787645364, text: Goodbye! } @@ -304,7 +317,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -318,7 +331,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -333,7 +346,7 @@ Status: { $type: Status.Committed }, - CallerIdentity: Identity_2, + CallerIdentity: Identity_3, CallerConnectionId: Guid_1, EnergyConsumed: {}, Reducer: { @@ -346,12 +359,12 @@ SetReducerFlags: {} }, oldUser: { - identity: Identity_2, + identity: Identity_3, name: B, online: true }, newUser: { - identity: Identity_2, + identity: Identity_3, name: B, online: false } @@ -404,7 +417,7 @@ }, User: { Identity: {}, - Count: 2 + Count: 3 } }, Reducers: {}, @@ -420,7 +433,7 @@ SetReducerFlags: {} }, message: { - sender: Identity_2, + sender: Identity_3, sent: 1718487775346381, text: Hello, A! } @@ -450,7 +463,7 @@ SetReducerFlags: {} }, message: { - sender: Identity_2, + sender: Identity_3, sent: 1718487787645364, text: Goodbye! } @@ -481,7 +494,7 @@ SetReducerFlags: {} }, message: { - sender: Identity_2, + sender: Identity_3, sent: 1718487775346381, text: Hello, A! } @@ -511,7 +524,7 @@ SetReducerFlags: {} }, message: { - sender: Identity_2, + sender: Identity_3, sent: 1718487787645364, text: Goodbye! } @@ -541,6 +554,10 @@ }, { identity: Identity_2, + online: true + }, + { + identity: Identity_3, name: B, online: false } @@ -552,7 +569,7 @@ text: Goodbye! }, { - sender: Identity_2, + sender: Identity_3, sent: 1718487787645364, text: Goodbye! }, @@ -562,7 +579,7 @@ text: Hello, B! }, { - sender: Identity_2, + sender: Identity_3, sent: 1718487775346381, text: Hello, A! } diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs index 9e32290..11c2fa7 100644 --- a/tests~/SnapshotTests.cs +++ b/tests~/SnapshotTests.cs @@ -303,7 +303,9 @@ public static IEnumerable SampleDump() 1, 366, [SampleUserInsert("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", null, true)] ), SampleTransactionUpdate(0, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", - 0, "unknown-reducer", 0, 40, [], null + 0, "unknown-reducer", 0, 40, [ +SampleUserInsert("k5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", null, true) + ], null ), SampleTransactionUpdate( 1718487763059031, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", @@ -369,7 +371,9 @@ public static IEnumerable SampleDump() 1, 2, 277, SampleUpdate(MESSAGE_TABLE_ID, MESSAGE_TABLE_NAME, [], []) ), SampleTransactionUpdate(0, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", - 0, "unknown-reducer", 0, 40, [], null + 0, "unknown-reducer", 0, 40, [ + SampleUserInsert("k5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", null, true) + ], null ), SampleTransactionUpdate( 1718487763059031, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", @@ -476,10 +480,6 @@ public async Task VerifySampleDump(string dumpName, ServerMessage[] sampleDumpPa } ); -#pragma warning disable CS0612 // Using obsolete API - client.onUnhandledReducerError += (exception) => - events.Add("OnUnhandledReducerError", exception); -#pragma warning restore CS0612 // Using obsolete API client.Reducers.OnSendMessage += (eventContext, _text) => events.Add("OnSendMessage", eventContext); client.Reducers.OnSetName += (eventContext, _name) => events.Add("OnSetName", eventContext); diff --git a/tools~/update-against-stdb.sh b/tools~/update-against-stdb.sh new file mode 100644 index 0000000..7b5b556 --- /dev/null +++ b/tools~/update-against-stdb.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Do everything needed to update this repo from an upstream STDB clone. + +set -ueox pipefail + +STDB_PATH="$1" +SDK_PATH="$(dirname "$0")/.." +SDK_PATH="$(realpath "$SDK_PATH")" + +"$SDK_PATH/tools~/write-nuget-config.sh" "$STDB_PATH" +"$SDK_PATH/tools~/gen-client-api.sh" "$STDB_PATH" +"$SDK_PATH/tools~/gen-quickstart.sh" "$STDB_PATH" +dotnet nuget locals all --clear +dotnet pack "$STDB_PATH/crates/bindings-csharp" +rm -rf "$SDK_PATH/packages" +dotnet pack +dotnet test +pushd "$SDK_PATH"; git checkout -- 'packages/*.meta' 'packages/**/*.meta' packages/.gitignore; popd + + diff --git a/unity-tests~ b/unity-tests~ index 1cb15a3..3b4f71a 160000 --- a/unity-tests~ +++ b/unity-tests~ @@ -1 +1 @@ -Subproject commit 1cb15a3aa43a70cbe918e5a4654c3b5002cc288c +Subproject commit 3b4f71a2f6854b91554dc38597c03f88f91b4966