Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
636775e
refactor(runtime): start grain activation synchronously
ReubenBond Aug 12, 2026
23c181e
test(runtime): cover synchronous activation start
ReubenBond Aug 19, 2026
6d70649
test(runtime): verify concurrent default context use
ReubenBond Aug 19, 2026
ee07701
refactor(runtime): capture clean context via thread pool
ReubenBond Aug 20, 2026
6b55ad4
fix(runtime): preserve activation scheduler ownership
ReubenBond Aug 20, 2026
30d0efd
fix(runtime): preserve activation continuation context
ReubenBond Aug 20, 2026
8de959c
fix(runtime): preserve activation startup ordering
ReubenBond Aug 20, 2026
00028fd
refactor(runtime): use one-shot activation startup
ReubenBond Aug 21, 2026
01a2f66
refactor(runtime): expose grain context startup
ReubenBond Aug 21, 2026
15f7459
style(runtime): remove unused scheduler imports
ReubenBond Aug 21, 2026
5e6ae67
refactor(runtime): simplify activation startup protocol
ReubenBond Aug 24, 2026
0d06b14
test(runtime): cover activation startup lifecycle
ReubenBond Aug 24, 2026
c0bcd39
fix(runtime): balance activation metrics on abort
ReubenBond Aug 24, 2026
9a38d0f
fix(runtime): harden activation startup cleanup
ReubenBond Aug 24, 2026
1f68aab
fix(runtime): unpublish aborted activation startup
ReubenBond Aug 24, 2026
7459ad8
fix(runtime): unpublish failed activation start
ReubenBond Aug 24, 2026
c22f60a
fix(runtime): complete aborted activation startup
ReubenBond Aug 27, 2026
dd75566
fix(runtime): terminate aborted activation startup
ReubenBond Aug 27, 2026
202dba9
fix(runtime): reject requests after startup abort
ReubenBond Aug 27, 2026
cd82eb5
fix(runtime): preserve abort compatibility
ReubenBond Aug 27, 2026
a919a1c
fix(runtime): defer aborted startup cleanup
ReubenBond Aug 27, 2026
9164679
fix(runtime): dispose failed rehydration context
ReubenBond Aug 27, 2026
5d59011
test(runtime): propagate test cancellation
ReubenBond Aug 28, 2026
1cdaf2d
style(test): remove unused activation imports
ReubenBond Aug 28, 2026
c867151
fix(test): restore metrics namespace
ReubenBond Aug 28, 2026
dd0952b
fix(test): restore invocation namespace
ReubenBond Aug 28, 2026
cb08b32
fix(test): restore code generation namespace
ReubenBond Aug 28, 2026
19d2e79
fix(runtime): preserve startup failure details
ReubenBond Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 24 additions & 15 deletions src/Orleans.Runtime/Activation/ActivationDataActivatorProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,13 @@ public bool TryGet(GrainType grainType, [NotNullWhen(true)] out IGrainContextAct
return true;
}

private partial class ActivationDataActivator : IGrainContextActivator
private partial class ActivationDataActivator : IPreparedGrainContextActivator
{
private readonly IOptions<SchedulingOptions> _schedulingOptions;
private readonly IGrainActivator _grainActivator;
private readonly IServiceProvider _serviceProvider;
private readonly GrainTypeSharedContext _sharedComponents;
private readonly Func<IGrainContext, WorkItemGroup> _createWorkItemGroup;
private readonly Action<object?> _startActivation;

public ActivationDataActivator(
IGrainActivator grainActivator,
Expand All @@ -73,30 +72,40 @@ public ActivationDataActivator(
context,
_schedulingOptions,
schedulerInstruments);
_startActivation = state => ((ActivationData)state!).Start(_grainActivator);
}

public IGrainContext CreateContext(GrainAddress activationAddress, IConfigureGrainContext[] configureActions)
{
var preparedContext = CreatePreparedContext(activationAddress, configureActions);
using var startup = preparedContext.Start();
return preparedContext.Context;
}

public PreparedGrainContext CreatePreparedContext(
GrainAddress activationAddress,
IConfigureGrainContext[] configureActions)
{
var context = new ActivationData(
activationAddress,
_createWorkItemGroup,
_serviceProvider,
_sharedComponents);
_sharedComponents,
_grainActivator);

foreach (var configure in configureActions)
try
{
configure.Configure(context);
}
foreach (var configure in configureActions)
{
configure.Configure(context);
}

using var ecSuppressor = ExecutionContext.SuppressFlow();
_ = Task.Factory.StartNew(
_startActivation,
context,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
context.ActivationTaskScheduler);
return context;
return new(context, (IGrainContextStartup)context);
}
catch
{
((IGrainContextStartup)context).Abort();
throw;
}
}
}
}
Expand Down
82 changes: 81 additions & 1 deletion src/Orleans.Runtime/Activation/IGrainContextActivator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,21 @@ public GrainContextActivator(
/// <param name="address">The grain address.</param>
/// <returns>The grain context.</returns>
public IGrainContext CreateInstance(GrainAddress address)
{
var preparedContext = CreatePreparedContext(address);
using var startup = preparedContext.Start();
return preparedContext.Context;
}

internal PreparedGrainContext CreatePreparedContext(GrainAddress address)
{
var grainId = address.GrainId;
if (!_activators.TryGetValue(grainId.Type, out var activator))
{
activator = this.CreateActivator(grainId.Type);
}

return activator.Activator.CreateContext(address, activator.ConfigureActions);
return PreparedGrainContext.Create(activator.Activator, address, activator.ConfigureActions);
}

private (IGrainContextActivator, IConfigureGrainContext[]) CreateActivator(GrainType grainType)
Expand Down Expand Up @@ -134,6 +141,79 @@ public interface IGrainContextActivator
public IGrainContext CreateContext(GrainAddress address, IConfigureGrainContext[] configureActions);
}

internal interface IPreparedGrainContextActivator : IGrainContextActivator
{
PreparedGrainContext CreatePreparedContext(
GrainAddress address,
IConfigureGrainContext[] configureActions);
}

internal readonly struct PreparedGrainContext(IGrainContext context, IGrainContextStartup? startup)
{
private readonly IGrainContext? _context = context;
private readonly IGrainContextStartup? _startup = startup;

public IGrainContext Context
=> _context ?? throw new InvalidOperationException("The grain context activation is not initialized.");

public bool HasStartup => _startup is not null;

public static PreparedGrainContext Create(
IGrainContextActivator activator,
GrainAddress address,
IConfigureGrainContext[] configureActions) =>
activator is IPreparedGrainContextActivator preparedActivator
? preparedActivator.CreatePreparedContext(address, configureActions)
: new(activator.CreateContext(address, configureActions), startup: null);

public IDisposable Start()
{
if (_startup is not { } startup)
{
return NoopDisposable.Instance;
}

try
{
return startup.Start();
}
catch (Exception startupException)
{
try
{
startup.Abort();
}
catch (Exception abortException)
{
throw new AggregateException(
"Grain context startup failed and aborting the startup also failed.",
startupException,
abortException);
}

throw;
}
}

public void Abort() => _startup?.Abort();

private sealed class NoopDisposable : IDisposable
{
public static NoopDisposable Instance { get; } = new();

public void Dispose()
{
}
}
}

internal interface IGrainContextStartup
{
IDisposable Start();

void Abort();
}

/// <summary>
/// Provides a <see cref="IConfigureGrainContext"/> instance for the provided grain type.
/// </summary>
Expand Down
Loading