@@ -27,7 +27,9 @@ use std::path::PathBuf;
2727const INDENT : & str = " " ;
2828
2929const REDUCER_EVENTS : & str = r#"
30- public interface IRemoteDbContext : IDbContext<RemoteTables, RemoteReducers, SetReducerFlags, SubscriptionBuilder> { }
30+ public interface IRemoteDbContext : IDbContext<RemoteTables, RemoteReducers, SetReducerFlags, SubscriptionBuilder> {
31+ public event Action<ReducerEventContext, Exception>? OnUnhandledReducerError;
32+ }
3133
3234 public sealed class EventContext : IEventContext, IRemoteDbContext
3335 {
@@ -88,6 +90,13 @@ const REDUCER_EVENTS: &str = r#"
8890 /// Get this connection's <c>ConnectionId</c>.
8991 /// </summary>
9092 public ConnectionId ConnectionId => conn.ConnectionId;
93+ /// <summary>
94+ /// Register a callback to be called when a reducer with no handler returns an error.
95+ /// </summary>
96+ public event Action<ReducerEventContext, Exception>? OnUnhandledReducerError {
97+ add => Reducers.InternalOnUnhandledReducerError += value;
98+ remove => Reducers.InternalOnUnhandledReducerError -= value;
99+ }
91100
92101 internal EventContext(DbConnection conn, Event<Reducer> Event)
93102 {
@@ -154,6 +163,13 @@ const REDUCER_EVENTS: &str = r#"
154163 /// Get this connection's <c>ConnectionId</c>.
155164 /// </summary>
156165 public ConnectionId ConnectionId => conn.ConnectionId;
166+ /// <summary>
167+ /// Register a callback to be called when a reducer with no handler returns an error.
168+ /// </summary>
169+ public event Action<ReducerEventContext, Exception>? OnUnhandledReducerError {
170+ add => Reducers.InternalOnUnhandledReducerError += value;
171+ remove => Reducers.InternalOnUnhandledReducerError -= value;
172+ }
157173
158174 internal ReducerEventContext(DbConnection conn, ReducerEvent<Reducer> reducerEvent)
159175 {
@@ -225,6 +241,13 @@ const REDUCER_EVENTS: &str = r#"
225241 /// Get this connection's <c>ConnectionId</c>.
226242 /// </summary>
227243 public ConnectionId ConnectionId => conn.ConnectionId;
244+ /// <summary>
245+ /// Register a callback to be called when a reducer with no handler returns an error.
246+ /// </summary>
247+ public event Action<ReducerEventContext, Exception>? OnUnhandledReducerError {
248+ add => Reducers.InternalOnUnhandledReducerError += value;
249+ remove => Reducers.InternalOnUnhandledReducerError -= value;
250+ }
228251
229252 internal ErrorContext(DbConnection conn, Exception error)
230253 {
@@ -287,6 +310,13 @@ const REDUCER_EVENTS: &str = r#"
287310 /// Get this connection's <c>ConnectionId</c>.
288311 /// </summary>
289312 public ConnectionId ConnectionId => conn.ConnectionId;
313+ /// <summary>
314+ /// Register a callback to be called when a reducer with no handler returns an error.
315+ /// </summary>
316+ public event Action<ReducerEventContext, Exception>? OnUnhandledReducerError {
317+ add => Reducers.InternalOnUnhandledReducerError += value;
318+ remove => Reducers.InternalOnUnhandledReducerError -= value;
319+ }
290320
291321 internal SubscriptionEventContext(DbConnection conn)
292322 {
@@ -639,7 +669,19 @@ impl Lang for Csharp<'_> {
639669 "public bool Invoke{func_name_pascal_case}(ReducerEventContext ctx, Reducer.{func_name_pascal_case} args)"
640670 ) ;
641671 indented_block ( output, |output| {
642- writeln ! ( output, "if (On{func_name_pascal_case} == null) return false;" ) ;
672+ writeln ! ( output, "if (On{func_name_pascal_case} == null)" ) ;
673+ indented_block ( output, |output| {
674+ writeln ! ( output, "if (InternalOnUnhandledReducerError != null)" ) ;
675+ indented_block ( output, |output| {
676+ writeln ! ( output, "switch(ctx.Event.Status)" ) ;
677+ indented_block ( output, |output| {
678+ writeln ! ( output, "case Status.Failed(var reason): InternalOnUnhandledReducerError(ctx, new Exception(reason)); break;" ) ;
679+ writeln ! ( output, "case Status.OutOfEnergy(var _): InternalOnUnhandledReducerError(ctx, new Exception(\" out of energy\" )); break;" ) ;
680+ } ) ;
681+ } ) ;
682+ writeln ! ( output, "return false;" ) ;
683+ } ) ;
684+
643685 writeln ! ( output, "On{func_name_pascal_case}(" ) ;
644686 // Write out arguments one per line
645687 {
@@ -706,6 +748,10 @@ impl Lang for Csharp<'_> {
706748 "internal RemoteReducers(DbConnection conn, SetReducerFlags flags) : base(conn) => SetCallReducerFlags = flags;"
707749 ) ;
708750 writeln ! ( output, "internal readonly SetReducerFlags SetCallReducerFlags;" ) ;
751+ writeln ! (
752+ output,
753+ "internal event Action<ReducerEventContext, Exception>? InternalOnUnhandledReducerError;"
754+ )
709755 } ) ;
710756 writeln ! ( output) ;
711757
@@ -828,6 +874,14 @@ impl Lang for Csharp<'_> {
828874 writeln ! ( output) ;
829875
830876 writeln ! ( output, "public SubscriptionBuilder SubscriptionBuilder() => new(this);" ) ;
877+ writeln ! (
878+ output,
879+ "public event Action<ReducerEventContext, Exception> OnUnhandledReducerError"
880+ ) ;
881+ indented_block ( output, |output| {
882+ writeln ! ( output, "add => Reducers.InternalOnUnhandledReducerError += value;" ) ;
883+ writeln ! ( output, "remove => Reducers.InternalOnUnhandledReducerError -= value;" ) ;
884+ } ) ;
831885 } ) ;
832886
833887 vec ! [ ( "SpacetimeDBClient.g.cs" . to_owned( ) , output. into_inner( ) ) ]
0 commit comments