Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8b47751
refactor(runtime): start grain activation synchronously
ReubenBond Aug 12, 2026
696884a
test(runtime): cover synchronous activation start
ReubenBond Aug 19, 2026
53d4fac
test(runtime): verify concurrent default context use
ReubenBond Aug 19, 2026
a439033
refactor(runtime): capture clean context via thread pool
ReubenBond Aug 20, 2026
5322ae1
fix(runtime): preserve activation scheduler ownership
ReubenBond Aug 20, 2026
8d1e95b
fix(runtime): preserve activation continuation context
ReubenBond Aug 20, 2026
762238d
fix(runtime): preserve activation startup ordering
ReubenBond Aug 20, 2026
ab2c21e
refactor(runtime): use one-shot activation startup
ReubenBond Aug 21, 2026
bcc5c87
refactor(runtime): expose grain context startup
ReubenBond Aug 21, 2026
7624d78
style(runtime): remove unused scheduler imports
ReubenBond Aug 21, 2026
a69d6c7
refactor(runtime): simplify activation startup protocol
ReubenBond Aug 24, 2026
cf42f86
test(runtime): cover activation startup lifecycle
ReubenBond Aug 24, 2026
fd127e6
fix(runtime): balance activation metrics on abort
ReubenBond Aug 24, 2026
657bee3
fix(runtime): harden activation startup cleanup
ReubenBond Aug 24, 2026
30cad27
fix(runtime): unpublish aborted activation startup
ReubenBond Aug 24, 2026
08edd02
fix(runtime): unpublish failed activation start
ReubenBond Aug 24, 2026
d71118f
fix(runtime): complete aborted activation startup
ReubenBond Aug 27, 2026
affcd69
fix(runtime): terminate aborted activation startup
ReubenBond Aug 27, 2026
83c816a
fix(runtime): reject requests after startup abort
ReubenBond Aug 27, 2026
51b4fe4
fix(runtime): preserve abort compatibility
ReubenBond Aug 27, 2026
016e209
fix(runtime): defer aborted startup cleanup
ReubenBond Aug 27, 2026
d23975b
fix(runtime): dispose failed rehydration context
ReubenBond Aug 27, 2026
6fbdd7b
test(runtime): propagate test cancellation
ReubenBond Aug 28, 2026
617528b
style(test): remove unused activation imports
ReubenBond Aug 28, 2026
bb545e1
fix(test): restore metrics namespace
ReubenBond Aug 28, 2026
02bf51b
fix(test): restore invocation namespace
ReubenBond Aug 28, 2026
f6f2ac3
fix(test): restore code generation namespace
ReubenBond Aug 28, 2026
f2cdacf
fix(runtime): preserve startup failure details
ReubenBond Aug 28, 2026
ca17c11
fix(runtime): synchronize startup abort state
ReubenBond Sep 5, 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
Loading