Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 20 additions & 4 deletions src/Orleans.Core.Abstractions/Core/Grain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Orleans;
/// </summary>
public abstract partial class Grain : IGrainBase, IAddressable
{
private IGrainRuntime? _grainRuntime;

// Do not use this directly because we currently don't provide a way to inject it;
// any interaction with it will result in non unit-testable code. Any behavior that can be accessed
// from within client code (including subclasses of this class), should be exposed through IGrainRuntime.
Expand All @@ -23,7 +25,7 @@ public abstract partial class Grain : IGrainBase, IAddressable

public GrainReference GrainReference { get { return GrainContext.GrainReference; } }

internal IGrainRuntime Runtime { get; }
internal IGrainRuntime Runtime => _grainRuntime ??= GetGrainRuntime()!;

/// <summary>
/// Gets an object which can be used to access other grains. Null if this grain is not associated with a Runtime, such as when created directly for unit testing.
Expand Down Expand Up @@ -54,9 +56,7 @@ protected Grain() : this(RuntimeContext.Current!, grainRuntime: null)
protected Grain(IGrainContext grainContext, IGrainRuntime? grainRuntime = null)
{
GrainContext = grainContext;

// ! The runtime ensures that this is not null and Unit testing frameworks must make sure that this is not null.
Runtime = grainRuntime ?? grainContext?.ActivationServices.GetService<IGrainRuntime>()!;
_grainRuntime = grainRuntime;
}

/// <summary>
Expand Down Expand Up @@ -163,6 +163,22 @@ protected void DelayDeactivation(TimeSpan timeSpan)
/// <param name="cancellationToken">A cancellation token which signals when deactivation should complete promptly.</param>
public virtual Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken) => Task.CompletedTask;

private IGrainRuntime? GetGrainRuntime()
{
var grainContext = GrainContext;
if (grainContext is null)
{
return null;
}

if (grainContext.GetComponent(typeof(IGrainRuntime)) is IGrainRuntime grainRuntime)
{
return grainRuntime;
}

return grainContext.ActivationServices.GetService<IGrainRuntime>();
}

internal void EnsureRuntime()
{
if (Runtime == null)
Expand Down
10 changes: 10 additions & 0 deletions src/Orleans.Runtime/Catalog/GrainTypeSharedContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ private static TimeSpan GetCollectionAgeLimit(GrainType grainType, Type grainCla
return (TComponent)Logger;
}

if (typeof(TComponent) == typeof(IGrainRuntime) && Runtime is TComponent runtime)
{
return runtime;
}

if (_components is null) return default;
_components.TryGetValue(typeof(TComponent), out var resultObj);
return (TComponent?)resultObj;
Expand All @@ -131,6 +136,11 @@ private static TimeSpan GetCollectionAgeLimit(GrainType grainType, Type grainCla
return Logger;
}

if (componentType == typeof(IGrainRuntime))
{
return Runtime;
}

if (_components is null) return default;
_components.TryGetValue(componentType, out var resultObj);
return resultObj;
Expand Down
Loading