Skip to content

Commit fe2b44b

Browse files
Widen ActorTaskScheduler(ActorCell) ctor to protected internal (#8158)
The two virtual hooks OnBeforeTaskStarted / OnAfterTaskCompleted have always been protected, clearly intended as extension points for libraries that need to observe async message handler lifetimes. But the ctor was internal, blocking any external subclass from actually hooking them without reflection or runtime codegen. Widening the ctor to protected internal finishes the extension point that was already half-exposed. protected lets external libraries subclass; the internal part preserves the existing new ActorTaskScheduler(this) call site in ActorCell without requiring a derived type there. Motivation: Phobos (the Akka.NET observability plugin) needs to subclass ActorTaskScheduler to keep akka.msg.recv spans open for the full duration of ReceiveAsync / CommandAsync handlers. Today the span closes at the first await yield point, hiding all post-await work from traces. Customers running Phobos on both .NET and .NET Framework hit this, and we need a cross-runtime fix — IgnoresAccessChecksTo works only on CoreCLR, reflection can't synthesize a subclass with an inaccessible base ctor, and runtime codegen is AOT-hostile. Widening the ctor is the clean fix. No behavior change. Pure access widening, no caller breaks.
1 parent 01edcb1 commit fe2b44b

3 files changed

Lines changed: 18 additions & 3 deletions

File tree

src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2724,6 +2724,7 @@ namespace Akka.Dispatch
27242724
}
27252725
public class ActorTaskScheduler : System.Threading.Tasks.TaskScheduler
27262726
{
2727+
protected ActorTaskScheduler(Akka.Actor.ActorCell actorCell) { }
27272728
public object CurrentMessage { get; }
27282729
public override int MaximumConcurrencyLevel { get; }
27292730
protected override System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task> GetScheduledTasks() { }

src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,6 +2742,7 @@ namespace Akka.Dispatch
27422742
}
27432743
public class ActorTaskScheduler : System.Threading.Tasks.TaskScheduler
27442744
{
2745+
protected ActorTaskScheduler(Akka.Actor.ActorCell actorCell) { }
27452746
public object CurrentMessage { get; }
27462747
public override int MaximumConcurrencyLevel { get; }
27472748
protected override System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task> GetScheduledTasks() { }

src/core/Akka/Dispatch/ActorTaskScheduler.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,23 @@ protected virtual void OnBeforeTaskStarted() { }
3737
protected virtual void OnAfterTaskCompleted() { }
3838

3939
/// <summary>
40-
/// TBD
40+
/// Creates a new <see cref="ActorTaskScheduler"/> bound to the given
41+
/// <see cref="ActorCell"/>.
42+
///
43+
/// Exposed as <c>protected internal</c> so external libraries (notably
44+
/// Phobos, the Akka.NET observability plugin) can subclass
45+
/// <see cref="ActorTaskScheduler"/> and override
46+
/// <see cref="OnBeforeTaskStarted"/> / <see cref="OnAfterTaskCompleted"/>
47+
/// to observe async message handler lifetimes without reflection or
48+
/// runtime codegen. The two virtual hooks have always been
49+
/// <c>protected</c>, so widening the constructor to match finishes an
50+
/// extension point that was already half-exposed. The <c>internal</c>
51+
/// portion preserves the existing <c>new ActorTaskScheduler(this)</c>
52+
/// call site inside <see cref="ActorCell"/> without requiring a
53+
/// derived type.
4154
/// </summary>
42-
/// <param name="actorCell">TBD</param>
43-
internal ActorTaskScheduler(ActorCell actorCell)
55+
/// <param name="actorCell">The cell this scheduler is bound to.</param>
56+
protected internal ActorTaskScheduler(ActorCell actorCell)
4457
{
4558
_actorCell = actorCell;
4659
}

0 commit comments

Comments
 (0)