Skip to content

Commit 55894ee

Browse files
authored
Merge pull request #4 from cernuto/feature/performance-and-reliability-optimizations
Optimizations with reliability changes
2 parents 18a7438 + 6104eb3 commit 55894ee

File tree

79 files changed

+3411
-662
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+3411
-662
lines changed

.claude/settings.local.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(tree:*)",
5+
"Bash(dotnet build:*)",
6+
"Bash(dotnet test:*)",
7+
"Bash(git checkout:*)",
8+
"Bash(git push:*)",
9+
"Bash(git remote add:*)"
10+
]
11+
}
12+
}

.editorconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,20 @@ dotnet_diagnostic.IDE0200.severity = warning
453453
dotnet_style_allow_multiple_blank_lines_experimental = false
454454
dotnet_diagnostic.IDE2000.severity = warning
455455

456+
# SignalR Hub methods are called by string name from clients - suppress async naming rule
457+
[**/Hubs/*.cs]
458+
dotnet_naming_rule.async_methods_should_end_with_async.severity = none
459+
460+
# ASP.NET Controller actions don't typically follow async naming conventions
461+
[**/Controllers/*.cs]
462+
dotnet_naming_rule.async_methods_should_end_with_async.severity = none
463+
464+
# Orleans grains with [PersistentState] attributes cannot use primary constructors
465+
# because attributes on constructor parameters cannot be applied to primary constructor parameters
466+
[**/SignalRConnectionHeartbeatGrain.cs]
467+
csharp_style_prefer_primary_constructors = false:none
468+
dotnet_diagnostic.IDE0290.severity = none
469+
456470
# Verify settings for test files
457471
[*.{received,verified}.{txt,xml,json}]
458472
charset = utf-8-bom

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,4 +646,7 @@ MigrationBackup/
646646
# Ionide (cross platform F# VS Code tools) working folder
647647
.ionide/
648648

649-
# End of https://www.toptal.com/developers/gitignore/api/intellij,intellij+all,macos,linux,windows,visualstudio,visualstudiocode,rider
649+
# End of https://www.toptal.com/developers/gitignore/api/intellij,intellij+all,macos,linux,windows,visualstudio,visualstudiocode,rider
650+
651+
# Claude Code temporary directories
652+
tmpclaude-*/
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"profiles": {
3+
"ManagedCode.Orleans.SignalR.Client": {
4+
"commandName": "Project",
5+
"launchBrowser": true,
6+
"environmentVariables": {
7+
"ASPNETCORE_ENVIRONMENT": "Development"
8+
},
9+
"applicationUrl": "https://localhost:56460;http://localhost:56463"
10+
}
11+
}
12+
}

ManagedCode.Orleans.SignalR.Core/Config/OrleansSignalROptions.cs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,102 @@ public class OrleansSignalROptions
5454
/// Used as a hint when determining how many partitions to allocate dynamically.
5555
/// </summary>
5656
public int GroupsPerPartitionHint { get; set; } = 1_000;
57+
58+
/// <summary>
59+
/// Maximum number of messages to queue per user when they are disconnected.
60+
/// Oldest messages are dropped when the limit is exceeded.
61+
/// The default value is 100.
62+
/// </summary>
63+
public int MaxQueuedMessagesPerUser { get; set; } = 100;
64+
65+
/// <summary>
66+
/// Number of consecutive failures before an observer is considered dead and removed.
67+
/// Set to 0 to disable failure tracking.
68+
/// The default value is 3.
69+
/// </summary>
70+
public int ObserverFailureThreshold { get; set; } = 3;
71+
72+
/// <summary>
73+
/// Time window for counting observer failures. Failures older than this are forgotten.
74+
/// The default value is 30 seconds.
75+
/// </summary>
76+
public TimeSpan ObserverFailureWindow { get; set; } = TimeSpan.FromSeconds(30);
77+
78+
/// <summary>
79+
/// Enables circuit breaker pattern for observers to prevent cascade failures.
80+
/// When enabled, failing observers are temporarily blocked from receiving messages.
81+
/// The default value is true.
82+
/// </summary>
83+
public bool EnableCircuitBreaker { get; set; } = true;
84+
85+
/// <summary>
86+
/// Duration to keep the circuit open (blocking requests) after failure threshold is reached.
87+
/// After this duration, the circuit transitions to half-open state for testing.
88+
/// The default value is 30 seconds.
89+
/// </summary>
90+
public TimeSpan CircuitBreakerOpenDuration { get; set; } = TimeSpan.FromSeconds(30);
91+
92+
/// <summary>
93+
/// Interval between test requests when circuit is in half-open state.
94+
/// The default value is 5 seconds.
95+
/// </summary>
96+
public TimeSpan CircuitBreakerHalfOpenTestInterval { get; set; } = TimeSpan.FromSeconds(5);
97+
98+
/// <summary>
99+
/// Grace period before an observer is hard-removed after a failure.
100+
/// During this period, messages are buffered and replayed if the observer recovers.
101+
/// This handles timing edge cases like GC pauses, network latency, or silo overload.
102+
/// Set to TimeSpan.Zero to disable grace period buffering.
103+
/// The default value is 10 seconds.
104+
/// </summary>
105+
public TimeSpan ObserverGracePeriod { get; set; } = TimeSpan.FromSeconds(10);
106+
107+
/// <summary>
108+
/// Maximum number of messages to buffer per observer during the grace period.
109+
/// Oldest messages are dropped when the limit is exceeded.
110+
/// The default value is 50.
111+
/// </summary>
112+
public int MaxBufferedMessagesPerObserver { get; set; } = 50;
113+
114+
/// <summary>
115+
/// Maximum number of connections allowed per partition grain.
116+
/// New connections are rejected when the limit is exceeded.
117+
/// Set to 0 to disable connection limits (not recommended for production).
118+
/// The default value is 100,000.
119+
/// </summary>
120+
public int MaxConnectionsPerPartition { get; set; } = 100_000;
121+
122+
/// <summary>
123+
/// Maximum number of groups per partition grain.
124+
/// New groups are rejected when the limit is exceeded.
125+
/// Set to 0 to disable group limits.
126+
/// The default value is 50,000.
127+
/// </summary>
128+
public int MaxGroupsPerPartition { get; set; } = 50_000;
129+
130+
/// <summary>
131+
/// Timeout for slow client message delivery.
132+
/// Connections that cannot receive messages within this time may be terminated.
133+
/// The default value is 10 seconds.
134+
/// </summary>
135+
public TimeSpan SlowClientTimeout { get; set; } = TimeSpan.FromSeconds(10);
136+
137+
/// <summary>
138+
/// Enables backpressure handling for slow clients.
139+
/// When enabled, messages to slow clients are dropped or the connection is terminated.
140+
/// The default value is true.
141+
/// </summary>
142+
public bool EnableSlowClientHandling { get; set; } = true;
143+
144+
/// <summary>
145+
/// Maximum number of pending messages allowed per connection before backpressure is applied.
146+
/// The default value is 1000.
147+
/// </summary>
148+
public int MaxPendingMessagesPerConnection { get; set; } = 1000;
149+
150+
/// <summary>
151+
/// Enables metrics collection for monitoring and diagnostics.
152+
/// The default value is true.
153+
/// </summary>
154+
public bool EnableMetrics { get; set; } = true;
57155
}

0 commit comments

Comments
 (0)