@cratis/pi 7.102.0 → 7.103.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +10 -1
  2. package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +2 -0
  3. package/package/corpus/harnesses/copilot/instructions/secrets.instructions.md +4 -0
  4. package/package/corpus/hooks/README.md +11 -1
  5. package/package/corpus/hooks/scripts/cratis-check-pr.mjs +12 -1
  6. package/package/corpus/hooks/scripts/cratis-guard-secrets.sh +79 -23
  7. package/package/corpus/hooks/scripts/cratis-guard-writes.sh +145 -40
  8. package/package/corpus/rules/profiles.md +10 -1
  9. package/package/corpus/rules/pull-requests.md +2 -0
  10. package/package/corpus/rules/secrets.md +4 -0
  11. package/package/corpus/skills/analyzing-dotnet-performance/LICENSE +23 -0
  12. package/package/corpus/skills/analyzing-dotnet-performance/NOTICE +36 -0
  13. package/package/corpus/skills/analyzing-dotnet-performance/SKILL.md +214 -0
  14. package/package/corpus/skills/analyzing-dotnet-performance/references/async-patterns.md +122 -0
  15. package/package/corpus/skills/analyzing-dotnet-performance/references/collections-and-linq.md +220 -0
  16. package/package/corpus/skills/analyzing-dotnet-performance/references/critical-patterns.md +291 -0
  17. package/package/corpus/skills/analyzing-dotnet-performance/references/io-and-serialization.md +135 -0
  18. package/package/corpus/skills/analyzing-dotnet-performance/references/memory-and-strings.md +219 -0
  19. package/package/corpus/skills/analyzing-dotnet-performance/references/regex-patterns.md +95 -0
  20. package/package/corpus/skills/analyzing-dotnet-performance/references/structural-patterns.md +38 -0
  21. package/package/corpus/skills/binlog-generation/LICENSE +23 -0
  22. package/package/corpus/skills/binlog-generation/NOTICE +22 -0
  23. package/package/corpus/skills/binlog-generation/SKILL.md +129 -0
  24. package/package/corpus/skills/check-bin-obj-clash/LICENSE +23 -0
  25. package/package/corpus/skills/check-bin-obj-clash/NOTICE +27 -0
  26. package/package/corpus/skills/check-bin-obj-clash/SKILL.md +127 -0
  27. package/package/corpus/skills/check-bin-obj-clash/references/common-causes-and-fixes.md +206 -0
  28. package/package/corpus/skills/coverage-analysis/LICENSE +23 -0
  29. package/package/corpus/skills/coverage-analysis/NOTICE +32 -0
  30. package/package/corpus/skills/coverage-analysis/SKILL.md +198 -0
  31. package/package/corpus/skills/coverage-analysis/references/guidelines.md +68 -0
  32. package/package/corpus/skills/coverage-analysis/references/output-format.md +91 -0
  33. package/package/corpus/skills/coverage-analysis/references/report-generation.md +58 -0
  34. package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +307 -0
  35. package/package/corpus/skills/coverage-analysis/scripts/Compute-CrapScores.ps1 +80 -0
  36. package/package/corpus/skills/coverage-analysis/scripts/CoverageData.ps1 +272 -0
  37. package/package/corpus/skills/coverage-analysis/scripts/Extract-MethodCoverage.ps1 +65 -0
  38. package/package/corpus/skills/csharp-refactoring/LICENSE +23 -0
  39. package/package/corpus/skills/csharp-refactoring/NOTICE +22 -0
  40. package/package/corpus/skills/csharp-refactoring/SKILL.md +175 -0
  41. package/package/corpus/skills/csharp-refactoring/references/operation-catalog.md +37 -0
  42. package/package/corpus/skills/directory-build-organization/LICENSE +23 -0
  43. package/package/corpus/skills/directory-build-organization/NOTICE +21 -0
  44. package/package/corpus/skills/directory-build-organization/SKILL.md +205 -0
  45. package/package/corpus/skills/directory-build-organization/references/common-patterns.md +56 -0
  46. package/package/corpus/skills/directory-build-organization/references/multi-level-examples.md +167 -0
  47. package/package/corpus/skills/directory-build-organization/references/targetframework-props-pitfall.md +54 -0
  48. package/package/corpus/skills/dotnet-aot-compat/LICENSE +23 -0
  49. package/package/corpus/skills/dotnet-aot-compat/NOTICE +18 -0
  50. package/package/corpus/skills/dotnet-aot-compat/SKILL.md +265 -0
  51. package/package/corpus/skills/dotnet-aot-compat/references/polyfills.md +43 -0
  52. package/package/corpus/skills/dotnet-trace-collect/LICENSE +23 -0
  53. package/package/corpus/skills/dotnet-trace-collect/NOTICE +65 -0
  54. package/package/corpus/skills/dotnet-trace-collect/SKILL.md +116 -0
  55. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-monitor.md +97 -0
  56. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect-linux.md +84 -0
  57. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect.md +91 -0
  58. package/package/corpus/skills/dotnet-trace-collect/references/perfcollect.md +200 -0
  59. package/package/corpus/skills/dotnet-trace-collect/references/perfview.md +141 -0
  60. package/package/corpus/skills/dotnet-trace-collect/references/tool-selection.md +160 -0
  61. package/package/corpus/skills/dump-collect/LICENSE +23 -0
  62. package/package/corpus/skills/dump-collect/NOTICE +40 -0
  63. package/package/corpus/skills/dump-collect/SKILL.md +97 -0
  64. package/package/corpus/skills/dump-collect/references/container-dumps.md +412 -0
  65. package/package/corpus/skills/dump-collect/references/coreclr-dumps.md +108 -0
  66. package/package/corpus/skills/dump-collect/references/nativeaot-dumps.md +280 -0
  67. package/package/corpus/skills/eliminate-redundant-restores/LICENSE +23 -0
  68. package/package/corpus/skills/eliminate-redundant-restores/NOTICE +19 -0
  69. package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +112 -0
  70. package/package/corpus/skills/extension-points/LICENSE +23 -0
  71. package/package/corpus/skills/extension-points/NOTICE +18 -0
  72. package/package/corpus/skills/extension-points/SKILL.md +248 -0
  73. package/package/corpus/skills/filter-syntax/LICENSE +23 -0
  74. package/package/corpus/skills/filter-syntax/NOTICE +17 -0
  75. package/package/corpus/skills/filter-syntax/SKILL.md +179 -0
  76. package/package/corpus/skills/including-generated-files/LICENSE +23 -0
  77. package/package/corpus/skills/including-generated-files/NOTICE +17 -0
  78. package/package/corpus/skills/including-generated-files/SKILL.md +139 -0
  79. package/package/corpus/skills/microbenchmarking/LICENSE +23 -0
  80. package/package/corpus/skills/microbenchmarking/NOTICE +36 -0
  81. package/package/corpus/skills/microbenchmarking/SKILL.md +131 -0
  82. package/package/corpus/skills/microbenchmarking/references/bdn-internals-and-tuning.md +143 -0
  83. package/package/corpus/skills/microbenchmarking/references/comparison-strategies.md +200 -0
  84. package/package/corpus/skills/microbenchmarking/references/diagnosers-and-exporters.md +150 -0
  85. package/package/corpus/skills/microbenchmarking/references/project-setup-and-running.md +189 -0
  86. package/package/corpus/skills/microbenchmarking/references/writing-benchmarks.md +310 -0
  87. package/package/corpus/skills/msbuild/LICENSE +23 -0
  88. package/package/corpus/skills/msbuild/NOTICE +55 -0
  89. package/package/corpus/skills/msbuild/SKILL.md +117 -0
  90. package/package/corpus/skills/msbuild/references/antipatterns/additional-antipatterns.md +291 -0
  91. package/package/corpus/skills/msbuild/references/antipatterns/incremental-build-inputs-outputs.md +57 -0
  92. package/package/corpus/skills/msbuild/references/antipatterns/private-assets.md +29 -0
  93. package/package/corpus/skills/msbuild/references/binlog-failure-analysis.md +85 -0
  94. package/package/corpus/skills/msbuild/references/binlog-generation.md +69 -0
  95. package/package/corpus/skills/msbuild/references/build-perf-baseline.md +493 -0
  96. package/package/corpus/skills/msbuild/references/build-perf-diagnostics.md +268 -0
  97. package/package/corpus/skills/msbuild/references/copy-to-output-directory.md +183 -0
  98. package/package/corpus/skills/msbuild/references/eval-performance.md +190 -0
  99. package/package/corpus/skills/msbuild/references/extension-points.md +281 -0
  100. package/package/corpus/skills/msbuild/references/incremental-build.md +365 -0
  101. package/package/corpus/skills/msbuild/references/msbuild-antipatterns.md +401 -0
  102. package/package/corpus/skills/orleans/LICENSE +21 -0
  103. package/package/corpus/skills/orleans/NOTICE +64 -0
  104. package/package/corpus/skills/orleans/SKILL.md +140 -0
  105. package/package/corpus/skills/orleans/references/anti-patterns.md +660 -0
  106. package/package/corpus/skills/orleans/references/configuration-api.md +933 -0
  107. package/package/corpus/skills/orleans/references/examples.md +66 -0
  108. package/package/corpus/skills/orleans/references/grain-api.md +784 -0
  109. package/package/corpus/skills/orleans/references/grains.md +75 -0
  110. package/package/corpus/skills/orleans/references/hosting.md +71 -0
  111. package/package/corpus/skills/orleans/references/implementation.md +591 -0
  112. package/package/corpus/skills/orleans/references/official-docs-index.md +250 -0
  113. package/package/corpus/skills/orleans/references/patterns.md +811 -0
  114. package/package/corpus/skills/orleans/references/persistence-api.md +495 -0
  115. package/package/corpus/skills/orleans/references/primitive-selection.md +35 -0
  116. package/package/corpus/skills/orleans/references/scheduling-and-services.md +295 -0
  117. package/package/corpus/skills/orleans/references/serialization-api.md +299 -0
  118. package/package/corpus/skills/orleans/references/streaming-api.md +396 -0
  119. package/package/corpus/skills/orleans/references/testing-patterns.md +210 -0
  120. package/package/corpus/skills/platform-detection/LICENSE +23 -0
  121. package/package/corpus/skills/platform-detection/NOTICE +17 -0
  122. package/package/corpus/skills/platform-detection/SKILL.md +230 -0
  123. package/package/corpus/skills/platform-detection/references/command-mode.md +27 -0
  124. package/package/corpus/skills/profiling/LICENSE +21 -0
  125. package/package/corpus/skills/profiling/NOTICE +50 -0
  126. package/package/corpus/skills/profiling/SKILL.md +144 -0
  127. package/package/corpus/skills/profiling/references/commands.md +439 -0
  128. package/package/corpus/skills/profiling/references/patterns.md +586 -0
  129. package/package/corpus/skills/profiling/references/profiling.md +190 -0
  130. package/package/corpus/skills/run-tests/LICENSE +23 -0
  131. package/package/corpus/skills/run-tests/NOTICE +19 -0
  132. package/package/corpus/skills/run-tests/SKILL.md +305 -0
  133. package/package/corpus/skills/target-authoring/LICENSE +23 -0
  134. package/package/corpus/skills/target-authoring/NOTICE +17 -0
  135. package/package/corpus/skills/target-authoring/SKILL.md +165 -0
  136. package/package/corpus/skills/vectorization/LICENSE +23 -0
  137. package/package/corpus/skills/vectorization/NOTICE +17 -0
  138. package/package/corpus/skills/vectorization/SKILL.md +189 -0
  139. package/package/profile-catalog.json +85 -1
  140. package/package.json +1 -1
@@ -0,0 +1,591 @@
1
+ # Implementation Details, Runtime Internals, and Testing
2
+
3
+ ## Contents
4
+
5
+ - Implementation Overview
6
+ - Grain Directory Internals
7
+ - Orleans Lifecycle
8
+ - Messaging Delivery Guarantees
9
+ - Scheduler
10
+ - Cluster Management
11
+ - Streams Implementation
12
+ - Load Balancing
13
+ - Unit Testing
14
+ - Tutorials, Samples, and Resource Pages
15
+ - API Reference and Source Entry Points
16
+ - Usage Guidance
17
+
18
+ Use this reference when architecture decisions depend on Orleans internals, scheduler rules, delivery guarantees, stream internals, or test-cluster behavior.
19
+
20
+ ## Implementation Overview
21
+
22
+ Orleans runtime is built on a few core subsystems:
23
+
24
+ ```mermaid
25
+ flowchart TD
26
+ C["Client / Gateway"] --> M["Messaging Layer"]
27
+ M --> S["Scheduler"]
28
+ S --> A["Activation Catalog"]
29
+ A --> G["Grain Directory"]
30
+ G --> P["Placement Director"]
31
+ M --> ST["Streaming Runtime"]
32
+ A --> PS["Persistence / State"]
33
+ CLM["Cluster Management"] --> G
34
+ CLM --> LB["Load Balancer"]
35
+ ```
36
+
37
+ Key principle: grains are virtual — they always exist logically, and the runtime activates/deactivates physical instances as needed. The grain directory maps identities to activations, the scheduler enforces single-threaded execution per grain, and the messaging layer routes calls across silos.
38
+
39
+ ## Grain Directory Internals
40
+
41
+ The grain directory maintains a mapping: `GrainId → (SiloAddress, ActivationId)`.
42
+
43
+ ### How Activation Works
44
+
45
+ 1. Client or grain makes a call to `GrainId`
46
+ 2. Runtime checks local cache for existing activation
47
+ 3. On cache miss, queries the grain directory
48
+ 4. If no activation exists, directory picks a silo (via placement) and creates one
49
+ 5. Directory registers the new activation
50
+ 6. Future calls route directly to the registered silo
51
+
52
+ ### Directory Partitioning
53
+
54
+ The default distributed directory uses a DHT (Distributed Hash Table):
55
+ - Each silo owns a range of the grain ID hash space
56
+ - Directory lookups are single-hop: hash the grain ID → find owning silo → query that silo
57
+ - On silo failure, its directory partition is rebuilt from surviving silos
58
+
59
+ ### Consistency
60
+
61
+ - **Default (eventually consistent)**: may allow brief duplicate activations during cluster instability. The duplicate is detected and one is deactivated.
62
+ - **Strong consistency (Orleans 10 preview)**: uses versioned range locks, 30 virtual nodes per silo. Prevents duplicate activations entirely. Enable with `builder.AddDistributedGrainDirectory()`.
63
+
64
+ ### Per-Grain-Type Directory
65
+
66
+ ```csharp
67
+ [GrainDirectory(GrainDirectoryName = "my-directory")]
68
+ public class MyGrain : Grain, IMyGrain { }
69
+
70
+ // Register external directory
71
+ siloBuilder.AddRedisGrainDirectory("my-directory", options => { });
72
+ ```
73
+
74
+ Available backends: In-Cluster (default), ADO.NET, Azure Table, Redis, Cosmos DB.
75
+
76
+ ## Orleans Lifecycle
77
+
78
+ Orleans uses an observable lifecycle pattern for ordered startup and shutdown of components.
79
+
80
+ ### Silo Lifecycle Stages
81
+
82
+ ```mermaid
83
+ flowchart LR
84
+ S1["First<br/>int.MinValue"] --> S2["RuntimeInitialize<br/>2000"]
85
+ S2 --> S3["RuntimeServices<br/>4000"]
86
+ S3 --> S4["RuntimeStorageServices<br/>6000"]
87
+ S4 --> S5["RuntimeGrainServices<br/>8000"]
88
+ S5 --> S6["ApplicationServices<br/>10000"]
89
+ S6 --> S7["BecomeActive<br/>Active-1"]
90
+ S7 --> S8["Active<br/>20000"]
91
+ S8 --> S9["Last<br/>int.MaxValue"]
92
+ ```
93
+
94
+ | Stage | Value | What Happens |
95
+ |---|---|---|
96
+ | `First` | `int.MinValue` | Earliest possible stage |
97
+ | `RuntimeInitialize` | 2000 | Threading initialization |
98
+ | `RuntimeServices` | 4000 | Networking, messaging, agents started |
99
+ | `RuntimeStorageServices` | 6000 | Storage providers initialized |
100
+ | `RuntimeGrainServices` | 8000 | Grain type management, membership joined, grain directory started |
101
+ | `ApplicationServices` | 10000 | Application-layer services initialized |
102
+ | `ValidateInitialConnectivity` | before `BecomeActive` | Orleans 10.2 validates initial peer connectivity while the silo is still `Joining` |
103
+ | `BecomeActive` | `Active - 1` | Silo joins the cluster |
104
+ | `Active` | 20000 | Ready for workload — grains can be activated |
105
+ | `Last` | `int.MaxValue` | Latest possible stage |
106
+
107
+ Shutdown reverses the order.
108
+
109
+ ### Participation API
110
+
111
+ Components participate via `ILifecycleParticipant<ISiloLifecycle>`:
112
+
113
+ ```csharp
114
+ public class MyComponent : ILifecycleParticipant<ISiloLifecycle>
115
+ {
116
+ public void Participate(ISiloLifecycle lifecycle)
117
+ {
118
+ lifecycle.Subscribe<MyComponent>(
119
+ ServiceLifecycleStage.ApplicationServices,
120
+ onStart: async ct =>
121
+ {
122
+ // Initialization logic
123
+ },
124
+ onStop: async ct =>
125
+ {
126
+ // Cleanup logic
127
+ });
128
+ }
129
+ }
130
+
131
+ // Register in DI
132
+ services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>, MyComponent>();
133
+ ```
134
+
135
+ ### Grain Lifecycle Stages
136
+
137
+ Grain-level lifecycle (distinct from silo lifecycle):
138
+
139
+ | Stage | Value | What Happens |
140
+ |---|---|---|
141
+ | `First` | `int.MinValue` | Earliest |
142
+ | `SetupState` | 1000 | Loads persistent state from storage |
143
+ | `Activate` | 2000 | Calls `OnActivateAsync` / `OnDeactivateAsync` |
144
+ | `Last` | `int.MaxValue` | Latest |
145
+
146
+ Override `Grain.Participate(IGrainLifecycle)` to hook into grain-level lifecycle.
147
+
148
+ ### Logging
149
+
150
+ At `Information` level on `Orleans.Runtime.SiloLifecycleSubject`, logs which components participate at each stage and timing.
151
+
152
+ ## Messaging Delivery Guarantees
153
+
154
+ ### Default: At-Most-Once
155
+
156
+ Orleans delivers messages **at most once** by default. A message is either delivered exactly once or not at all — never duplicated.
157
+
158
+ - Every message has an automatic configurable timeout
159
+ - On timeout, the caller's `Task` is faulted with a timeout exception
160
+ - **No automatic retries** by default
161
+
162
+ ### With Retries: At-Least-Once
163
+
164
+ If the application implements retry logic (e.g., via Polly), delivery becomes at-least-once: the message may arrive multiple times. Orleans does **not** deduplicate messages.
165
+
166
+ ### Timeout Behavior
167
+
168
+ ```csharp
169
+ // Global timeout
170
+ siloBuilder.Configure<SiloMessagingOptions>(options =>
171
+ {
172
+ options.ResponseTimeout = TimeSpan.FromSeconds(30); // default
173
+ });
174
+
175
+ // Per-method timeout
176
+ [ResponseTimeout("00:00:05")]
177
+ Task<Result> TimeSensitiveCall();
178
+ ```
179
+
180
+ ### Failure Scenarios
181
+
182
+ | Scenario | What Happens |
183
+ |---|---|
184
+ | Target silo alive | Message delivered, response returned |
185
+ | Target silo dead (detected) | Grain reactivated on another silo, message re-routed |
186
+ | Target silo dead (not yet detected) | Timeout → exception → caller retries → grain activates elsewhere |
187
+ | Network partition | Timeout → exception to caller |
188
+ | Grain method throws | Exception propagated back to caller |
189
+ | Grain `OnActivateAsync` throws | Activation fails, exception to caller |
190
+
191
+ ### Key Guarantee
192
+
193
+ With infinite retries, eventual delivery is guaranteed because grains never enter a permanent failure state — failed grains reactivate on another silo automatically.
194
+
195
+ ## Scheduler
196
+
197
+ Orleans uses a **cooperative, single-threaded-per-grain scheduler** built on the .NET Thread Pool.
198
+
199
+ ### Core Rules
200
+
201
+ 1. **Single-threaded execution**: a grain never executes on more than one thread simultaneously (unless `[Reentrant]`)
202
+ 2. **Turn-based**: each "turn" runs to the next `await` or completion. State only changes between turns.
203
+ 3. **No preemption**: long-running synchronous code blocks the grain's scheduler slot
204
+ 4. **Cooperative multitasking**: grains yield at `await` points
205
+
206
+ ### Task Scheduling Behavior Within Grain Code
207
+
208
+ | API | Where It Runs |
209
+ |---|---|
210
+ | `await task` | Resumes on grain scheduler |
211
+ | `Task.Factory.StartNew(delegate)` | Runs on grain scheduler |
212
+ | `ContinueWith(delegate)` | Runs on grain scheduler |
213
+ | `Task.WhenAll`, `Task.WhenAny` | Continuation on grain scheduler |
214
+ | `Task.Delay` | Continuation on grain scheduler |
215
+ | `Task.Run(delegate)` | Delegate on thread pool; `await` resumes on grain scheduler |
216
+ | `ConfigureAwait(false)` | **NEVER use** — escapes grain scheduler |
217
+ | `async void` | **NEVER use** in grain code |
218
+
219
+ ### Thread Pool Usage
220
+
221
+ Orleans runs grain turns on the .NET Thread Pool with cooperative scheduling. With proper async code, can achieve **90%+ CPU utilization** with stability.
222
+
223
+ ```csharp
224
+ // Background work on thread pool (OK)
225
+ var result = await Task.Run(() => CpuBoundWork(data));
226
+ // Resumes here on grain scheduler
227
+
228
+ // WRONG — deadlock risk
229
+ var bad = task.Result; // NEVER block in grain code
230
+ ```
231
+
232
+ ### Scheduling Options
233
+
234
+ ```csharp
235
+ siloBuilder.Configure<SchedulingOptions>(options =>
236
+ {
237
+ options.AllowCallChainReentrancy = false; // default
238
+ options.PerformDeadlockDetection = true; // default (dev)
239
+ });
240
+ ```
241
+
242
+ ### Reentrancy and Interleaving
243
+
244
+ Default non-reentrant: each request runs to completion. With `[Reentrant]`, multiple requests can interleave at `await` points. See grain-api.md `## Request Scheduling and Reentrancy` for full details.
245
+
246
+ ## Cluster Management
247
+
248
+ Fully distributed peer-to-peer membership protocol with no central coordinator.
249
+
250
+ ### Protocol Overview
251
+
252
+ ```mermaid
253
+ flowchart TD
254
+ S1["Silo 1"] -->|"Probe every 10s"| S2["Silo 2"]
255
+ S1 -->|"Probe every 10s"| S3["Silo 3"]
256
+ S2 -->|"Probe every 10s"| S1
257
+ S2 -->|"Probe every 10s"| S3
258
+ S3 -->|"Probe every 10s"| S1
259
+ S3 -->|"Probe every 10s"| S2
260
+ S1 & S2 & S3 -->|"IAmAlive every 30s"| MT["IMembershipTable<br/>(Azure Table / Redis / SQL / ...)"]
261
+ ```
262
+
263
+ ### Configuration
264
+
265
+ ```csharp
266
+ siloBuilder.Configure<ClusterMembershipOptions>(options =>
267
+ {
268
+ options.NumProbedSilos = 10; // how many silos monitor each silo (default 10 in 9.x+, was 3)
269
+ options.NumVotesForDeathDeclaration = 2; // votes needed to declare dead
270
+ options.DeathVoteExpirationTimeout = TimeSpan.FromSeconds(180); // vote TTL
271
+ options.ProbeTimeout = TimeSpan.FromSeconds(10); // probe interval
272
+ options.NumMissedProbesLimit = 3; // missed probes before suspicion
273
+ });
274
+ ```
275
+
276
+ ### Failure Detection Timeline
277
+
278
+ Typical: **~15 seconds** (Orleans 9+) from silo crash to detection.
279
+
280
+ 1. Monitoring silos send probes every 10 seconds
281
+ 2. After 3 missed probes (30s), silo is suspected
282
+ 3. 2 independent suspicions trigger death declaration
283
+ 4. Dead silo evicted from cluster, its activations destroyed
284
+ 5. Grains reactivate on other silos on next call
285
+
286
+ ### Protocol Properties
287
+
288
+ - Handles any number of simultaneous failures (f ≤ n), including full cluster restart
289
+ - Light table traffic: probes go direct silo-to-silo, not through `IMembershipTable`
290
+ - Self-monitoring with Lifeguard-inspired health scoring (unhealthy silos get increased probe timeouts)
291
+ - Indirect probing for accuracy improvement
292
+ - Table unavailability **never** causes false death declarations
293
+ - `IAmAlive` writes every 30 seconds for diagnostics and disaster recovery
294
+ - Ordered membership views with guaranteed connectivity on join
295
+ - Dead silos forced to terminate and restart as new processes
296
+
297
+ ### IMembershipTable Implementations
298
+
299
+ | Provider | Package |
300
+ |---|---|
301
+ | Azure Table Storage | `Microsoft.Orleans.Clustering.AzureStorage` |
302
+ | Redis | `Microsoft.Orleans.Clustering.Redis` |
303
+ | ADO.NET (SQL/PostgreSQL/MySQL/Oracle) | `Microsoft.Orleans.Clustering.AdoNet` |
304
+ | Cosmos DB | `Microsoft.Orleans.Clustering.Cosmos` |
305
+ | DynamoDB | `Microsoft.Orleans.Clustering.DynamoDB` |
306
+ | Consul | `Microsoft.Orleans.Clustering.Consul` |
307
+ | ZooKeeper | `Microsoft.Orleans.Clustering.ZooKeeper` |
308
+ | In-Memory (dev only) | built-in |
309
+
310
+ ## Streams Implementation
311
+
312
+ ### Architecture
313
+
314
+ The streaming runtime uses a **pulling model** with agents inside silos:
315
+
316
+ ```mermaid
317
+ flowchart LR
318
+ P["Producers"] -->|"OnNextAsync"| Q["Queue<br/>(Event Hubs / Azure Queue / Memory)"]
319
+ Q -->|"Pull"| PA["Pulling Agent<br/>(per silo)"]
320
+ PA -->|"Deliver"| G["Consumer Grains"]
321
+ PA -->|"Checkpoint"| CP["Checkpoint Store"]
322
+ ```
323
+
324
+ - **Pulling agents** run inside each silo, one per queue partition
325
+ - Agents pull batches of events from the underlying queue
326
+ - Events are dispatched to consumer grains via `IAsyncObserver<T>`
327
+ - Checkpoint position tracked in a separate storage provider
328
+
329
+ ### Pub-Sub System
330
+
331
+ Stream subscriptions are managed by `PubSubRendezvousGrain`:
332
+ - One rendezvous grain per `StreamId`
333
+ - Stores list of subscribers
334
+ - Persisted via the `"PubSubStore"` storage provider
335
+ - Implicit subscriptions (`[ImplicitStreamSubscription]`) registered automatically
336
+
337
+ ### Azure Queue Streams Implementation
338
+
339
+ NuGet: `Microsoft.Orleans.Streaming.AzureStorage`
340
+
341
+ ```csharp
342
+ siloBuilder.AddAzureQueueStreams("AQProvider", optionsBuilder =>
343
+ optionsBuilder.ConfigureAzureQueue(options =>
344
+ options.Configure(opt =>
345
+ {
346
+ opt.QueueServiceClient = new QueueServiceClient(endpoint, credential);
347
+ opt.QueueNames = new List<string> { "queue1", "queue2" }; // optional
348
+ })));
349
+ ```
350
+
351
+ Behavior:
352
+ - Uses Azure Storage Queues as the backing store
353
+ - Pulling agents poll queues at configurable intervals
354
+ - **Not rewindable** — cannot replay from arbitrary position
355
+ - Does **not** guarantee FIFO on failures (poison messages re-queued)
356
+ - Multiple queues for parallelism
357
+ - Automatic queue assignment to silo agents via consistent hashing
358
+
359
+ ### Event Hubs vs Azure Queue
360
+
361
+ | Feature | Event Hubs | Azure Queue |
362
+ |---|---|---|
363
+ | Rewindable | Yes (replay from token) | No |
364
+ | FIFO guarantee | Per partition | Not on failures |
365
+ | Throughput | High (millions/sec) | Moderate |
366
+ | Cost | Higher | Lower |
367
+ | Checkpointing | Yes (via checkpoint store) | Via queue dequeue |
368
+ | Use case | High-volume event streaming | Simple message queuing |
369
+
370
+ ## Load Balancing
371
+
372
+ Orleans uses multiple mechanisms to distribute load across the cluster:
373
+
374
+ ### Placement-Based Balancing
375
+
376
+ **Cratis qualification:** Resource-optimized placement is the default from Orleans 9.2; earlier versions used random placement.
377
+
378
+ The placement strategy determines where new activations are created:
379
+
380
+ | Strategy | Load Distribution |
381
+ |---|---|
382
+ | `ResourceOptimizedPlacement` (default 9.2+) | Weighted scoring: CPU (40), memory (20), available memory (20), max memory (5), activation count (15) |
383
+ | `ActivationCountBasedPlacement` | Power of Two Choices — pick two random silos, place on the one with fewer activations |
384
+ | `RandomPlacement` | Uniform random across compatible silos |
385
+ | `PreferLocalPlacement` | Local first, then random |
386
+
387
+ ### Activation Repartitioning (Experimental)
388
+
389
+ Monitors grain-to-grain communication patterns and migrates grains closer to frequent communication partners.
390
+
391
+ ```csharp
392
+ #pragma warning disable ORLEANSEXP001
393
+ siloBuilder.AddActivationRepartitioner();
394
+ #pragma warning restore ORLEANSEXP001
395
+ ```
396
+
397
+ Uses probabilistic tracking (sampling) and anchoring filters to limit migration churn.
398
+
399
+ ### Activation Rebalancing (Experimental, Orleans 10)
400
+
401
+ Cluster-wide redistribution for memory and activation count balance.
402
+
403
+ ```csharp
404
+ #pragma warning disable ORLEANSEXP002
405
+ siloBuilder.AddActivationRebalancer();
406
+ #pragma warning restore ORLEANSEXP002
407
+ ```
408
+
409
+ Uses entropy calculations to detect imbalance and session-based execution to coordinate rebalancing.
410
+
411
+ ### Memory-Based Activation Shedding (Orleans 9+)
412
+
413
+ Auto-deactivates least-recently-used grains when memory exceeds threshold:
414
+
415
+ ```csharp
416
+ services.Configure<GrainCollectionOptions>(options =>
417
+ {
418
+ options.EnableActivationSheddingOnMemoryPressure = true;
419
+ options.MemoryUsageLimitPercentage = 80; // start shedding
420
+ options.MemoryUsageTargetPercentage = 75; // stop shedding
421
+ options.MemoryUsagePollingPeriod = TimeSpan.FromSeconds(5);
422
+ });
423
+ ```
424
+
425
+ ## Unit Testing
426
+
427
+ ### InProcessTestCluster (Orleans 9+, Recommended)
428
+
429
+ ```csharp
430
+ // Setup
431
+ var builder = new InProcessTestClusterBuilder();
432
+ builder.ConfigureSilo((options, siloBuilder) =>
433
+ {
434
+ siloBuilder.AddMemoryGrainStorage("Default");
435
+ siloBuilder.AddMemoryGrainStorage("PubSubStore");
436
+ siloBuilder.UseInMemoryReminderService();
437
+ });
438
+ var cluster = builder.Build();
439
+ await cluster.DeployAsync();
440
+
441
+ // Test
442
+ var grain = cluster.Client.GetGrain<IPlayerGrain>("player-1");
443
+ await grain.UpdateScore(100);
444
+ var state = await grain.GetState();
445
+ Assert.Equal(100, state.Score);
446
+
447
+ // Cleanup
448
+ await cluster.DisposeAsync();
449
+ ```
450
+
451
+ Options: `InitialSilosCount` (default 1), `InitializeClientOnDeploy` (default true), `ConfigureFileLogging` (default true), `GatewayPerSilo` (default true).
452
+
453
+ ### Dynamic Silo Management
454
+
455
+ ```csharp
456
+ // Add silo to running cluster
457
+ var newSilo = await cluster.StartSiloAsync();
458
+
459
+ // Stop specific silo (simulate failure)
460
+ await cluster.StopSiloAsync(newSilo);
461
+
462
+ // Restart entire cluster
463
+ await cluster.RestartAsync();
464
+ ```
465
+
466
+ ### TestCluster (Legacy, Still Supported)
467
+
468
+ ```csharp
469
+ var builder = new TestClusterBuilder();
470
+ builder.AddSiloBuilderConfigurator<TestSiloConfigurator>();
471
+ var cluster = builder.Build();
472
+ cluster.Deploy(); // synchronous
473
+
474
+ public class TestSiloConfigurator : ISiloConfigurator
475
+ {
476
+ public void Configure(ISiloBuilder siloBuilder)
477
+ {
478
+ siloBuilder.AddMemoryGrainStorage("Default");
479
+ }
480
+ }
481
+ ```
482
+
483
+ ### Multi-Silo Testing
484
+
485
+ ```csharp
486
+ var builder = new InProcessTestClusterBuilder();
487
+ builder.InitialSilosCount = 3; // start with 3 silos
488
+
489
+ // Test placement, failover, reminders, etc.
490
+ var grain = cluster.Client.GetGrain<IMyGrain>("key");
491
+ await grain.DoWork();
492
+
493
+ // Kill a silo and verify grain reactivates
494
+ var siloToKill = cluster.Silos[1];
495
+ await cluster.StopSiloAsync(siloToKill);
496
+
497
+ // Grain auto-reactivates on next call
498
+ var result = await grain.DoWork(); // succeeds on different silo
499
+ ```
500
+
501
+ ### xUnit Fixture Sharing
502
+
503
+ ```csharp
504
+ public class ClusterFixture : IAsyncLifetime
505
+ {
506
+ public InProcessTestCluster Cluster { get; private set; } = null!;
507
+
508
+ public async Task InitializeAsync()
509
+ {
510
+ var builder = new InProcessTestClusterBuilder();
511
+ builder.ConfigureSilo((_, silo) => silo.AddMemoryGrainStorage("Default"));
512
+ Cluster = builder.Build();
513
+ await Cluster.DeployAsync();
514
+ }
515
+
516
+ public async Task DisposeAsync() => await Cluster.DisposeAsync();
517
+ }
518
+
519
+ [CollectionDefinition("Orleans")]
520
+ public class ClusterCollection : ICollectionFixture<ClusterFixture> { }
521
+
522
+ [Collection("Orleans")]
523
+ public class MyGrainTests
524
+ {
525
+ private readonly InProcessTestCluster _cluster;
526
+ public MyGrainTests(ClusterFixture fixture) => _cluster = fixture.Cluster;
527
+
528
+ [Fact]
529
+ public async Task TestGrainBehavior()
530
+ {
531
+ var grain = _cluster.Client.GetGrain<IMyGrain>("test");
532
+ var result = await grain.DoWork();
533
+ Assert.NotNull(result);
534
+ }
535
+ }
536
+ ```
537
+
538
+ ### Mocking Approach
539
+
540
+ ```csharp
541
+ // Override GrainFactory for mocking
542
+ public class TestableOrderGrain : OrderGrain
543
+ {
544
+ public new virtual IGrainFactory GrainFactory { get; set; }
545
+ }
546
+
547
+ // With Moq
548
+ var mockInventory = new Mock<IInventoryGrain>();
549
+ mockInventory.Setup(i => i.Reserve(It.IsAny<int>())).Returns(Task.CompletedTask);
550
+
551
+ var mockFactory = new Mock<IGrainFactory>();
552
+ mockFactory.Setup(f => f.GetGrain<IInventoryGrain>(It.IsAny<string>(), null))
553
+ .Returns(mockInventory.Object);
554
+ ```
555
+
556
+ Alternative: `OrleansTestKit` from OrleansContrib provides unit-test-friendly grain activation with less ceremony.
557
+
558
+ ## Tutorials, Samples, and Resource Pages
559
+
560
+ | Need | Official Source |
561
+ |---|---|
562
+ | Browse tutorials and samples | [Code samples overview](https://learn.microsoft.com/dotnet/orleans/tutorials-and-samples/) |
563
+ | Hello World tutorial | [Hello World](https://learn.microsoft.com/dotnet/orleans/tutorials-and-samples/overview-helloworld) |
564
+ | Orleans basics tutorial | [Tutorial 1](https://learn.microsoft.com/dotnet/orleans/tutorials-and-samples/tutorial-1) |
565
+ | Adventure game sample | [Adventure](https://learn.microsoft.com/dotnet/orleans/tutorials-and-samples/adventure) |
566
+ | Custom grain storage | [Custom storage sample](https://learn.microsoft.com/dotnet/orleans/tutorials-and-samples/custom-grain-storage) |
567
+ | Design principles | [Architecture principles](https://learn.microsoft.com/dotnet/orleans/resources/orleans-architecture-principles-and-approach) |
568
+ | When Orleans fits | [Applicability](https://learn.microsoft.com/dotnet/orleans/resources/orleans-thinking-big-and-small) |
569
+ | NuGet package map | [NuGet packages](https://learn.microsoft.com/dotnet/orleans/resources/nuget-packages) |
570
+ | Best practices | [Best practices](https://learn.microsoft.com/dotnet/orleans/resources/best-practices) |
571
+ | FAQ | [FAQ](https://learn.microsoft.com/dotnet/orleans/resources/frequently-asked-questions) |
572
+ | External links | [Links](https://learn.microsoft.com/dotnet/orleans/resources/links) |
573
+
574
+ ## API Reference and Source Entry Points
575
+
576
+ | Need | Official Source |
577
+ |---|---|
578
+ | Core API | [Orleans.Core](https://learn.microsoft.com/dotnet/api/orleans.core) |
579
+ | Runtime API | [Orleans.Runtime](https://learn.microsoft.com/dotnet/api/orleans.runtime) |
580
+ | Streams API | [Orleans.Streams](https://learn.microsoft.com/dotnet/api/orleans.streams) |
581
+ | Source repo | [dotnet/orleans](https://github.com/dotnet/orleans) |
582
+ | Official samples | [dotnet/samples Orleans](https://github.com/dotnet/samples/tree/main/orleans) |
583
+ | Repo samples README | [Samples README](https://github.com/dotnet/orleans/blob/main/samples/README.md) |
584
+
585
+ ## Usage Guidance
586
+
587
+ - Start here when the problem depends on scheduler rules, runtime delivery guarantees, stream internals, cluster management, or test-cluster behavior.
588
+ - Use grain-api.md for grain-level API details (reentrancy, timers, placement).
589
+ - Use configuration-api.md for operational setup (deployment, observability, providers).
590
+ - Use examples.md for example-first navigation.
591
+ - Use official-docs-index.md for the full documentation tree.