Server-side scenario execution: effects client replaces local engine

- client.Effects: typed effects + completion methods posting scenario callbacks
- client.Scenario reduced to TriggerAsync
- pending polling via Update() pump: 30s heartbeat + wait-deadline checks
- local engine, plan persistence (IPlanStateStore) and resume removed
- RealtimeService and realtime transports removed (relay never deployed)
- dead IPlanScheduler leftover removed
- models regenerated from openapi (ExecutionPlan/BoundaryNode gone, PendingEffect added)
This commit is contained in:
edmand46
2026-09-04 14:03:41 +03:00
parent 05dd30f31d
commit 6c590ca520
52 changed files with 1304 additions and 2040 deletions
+7 -13
View File
@@ -47,11 +47,11 @@ public sealed class RudderClient
/// <summary>Global quests.</summary>
public QuestsService Quests { get; }
/// <summary>Scenario runtime: triggers, node sessions, persistence.</summary>
/// <summary>Scenario trigger. Execution lives on the server.</summary>
public ScenarioService Scenario { get; }
/// <summary>Realtime websocket channel.</summary>
public RealtimeService Realtime { get; }
/// <summary>Pending scenario effects: subscriptions and completion callbacks.</summary>
public EffectsService Effects { get; }
internal RudderClientOptions Options { get; }
internal IRudderTransport Transport => Options.Transport!;
@@ -61,10 +61,7 @@ public sealed class RudderClient
/// <summary>Project key from <see cref="RudderClientOptions.ProjectKey"/>.</summary>
public string ProjectKey => Options.ProjectKey!;
/// <summary>Realtime URL from <see cref="RudderClientOptions.RealtimeUrl"/>.</summary>
public string? RealtimeUrl => Options.RealtimeUrl;
/// <summary>Time source used by the scenario runtime.</summary>
/// <summary>Time source used by the effects client.</summary>
public IClock Clock => Options.Clock ?? SystemClock.Instance;
/// <summary>
@@ -90,17 +87,16 @@ public sealed class RudderClient
Stores = new StoresService(this);
Leaderboards = new LeaderboardsService(this);
Inventory = new InventoryService(this);
Scenario = new ScenarioService(this);
BattlePass = new BattlePassService(this);
Quests = new QuestsService(this);
Realtime = new RealtimeService(this);
Effects = new EffectsService(this);
Scenario = new ScenarioService(this);
}
/// <summary>Pumps time-dependent services; call every frame.</summary>
public void Update(float deltaTime)
{
Scenario.Update(deltaTime);
Realtime.Update(deltaTime);
Effects.Update(deltaTime);
}
internal Task<TResponse> SendAsync<TRequest, TResponse>(
@@ -151,7 +147,6 @@ public sealed class RudderClient
}
catch (RudderAuthException)
{
// Session rejected — refresh once (single-flight) and retry the call once.
if (!await RefreshTokensAsync().ConfigureAwait(false))
throw;
@@ -218,7 +213,6 @@ public sealed class RudderClient
}
catch
{
// Transport-level failure during refresh — session is over.
}
}