Skip to content

Commit

Permalink
Add support for reentrancy predicate
Browse files Browse the repository at this point in the history
  • Loading branch information
yevhen committed Nov 3, 2016
1 parent f74baed commit 35c8115
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 2 deletions.
41 changes: 40 additions & 1 deletion Source/Orleankka.Tests/Features/Reentrant_messages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,34 @@ await stream2.Subscribe<string>(item =>
}
}

[Reentrant(nameof(IsReentrant))]
class TestReentrantByCallbackMethodActor : Actor
{
public static bool IsReentrant(object msg) => msg is ReentrantMessage;

readonly ActorState state = new ActorState();

async Task On(NonReentrantMessage x)
{
if (state.NonReentrantInProgress.Count > 0)
throw new InvalidOperationException("Can't be interleaved");

state.NonReentrantInProgress.Add(x.Id);
await Task.Delay(x.Delay);

state.NonReentrantInProgress.Remove(x.Id);
}

async Task<ActorState> On(ReentrantMessage x)
{
state.ReentrantInProgress.Add(x.Id);
await Task.Delay(x.Delay);

state.ReentrantInProgress.Remove(x.Id);
return state;
}
}

[RequiresSilo]
public class Tests
{
Expand All @@ -104,10 +132,21 @@ public void SetUp()
}

[Test]
public async Task When_received_message_via_Receive()
public async Task When_reentrant_determined_by_message_type()
{
var actor = system.FreshActorOf<TestActor>();
await TestReentrantReceive(actor);
}

[Test]
public async Task When_reentrant_determined_by_callback_method()
{
var actor = system.FreshActorOf<TestReentrantByCallbackMethodActor>();
await TestReentrantReceive(actor);
}

static async Task TestReentrantReceive(ActorRef actor)
{
var nr1 = actor.Tell(new NonReentrantMessage {Id = 1, Delay = TimeSpan.FromMilliseconds(500)});
await Task.Delay(50);

Expand Down
23 changes: 22 additions & 1 deletion Source/Orleankka/CSharp/ActorAttributes.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

using Orleans.CodeGeneration;

namespace Orleankka.CSharp
{
using Utility;
Expand Down Expand Up @@ -80,7 +83,25 @@ internal static Func<object, bool> Predicate(Type actor, out bool reentrant)

static Func<object, bool> DeterminedByCallbackMethod(Type actor, string callbackMethod)
{
throw new NotImplementedException();
var method = actor.GetMethod(callbackMethod, BindingFlags.Public | BindingFlags.Static);
if (method == null)
throw new InvalidOperationException(
$"Actor {actor.FullName} doesn't declare public static method " +
$"with name {callbackMethod} specified in Reentrant[] attribute");

if (method.ReturnType != typeof(bool) ||
method.GetParameters().Length != 1 ||
method.GetParameters()[0].ParameterType != typeof(object))
throw new InvalidOperationException(
$"Wrong signature of callback method {callbackMethod} " +
$"specified in Reentrant[] attribute for actor class {actor.FullName}. \n" +
$"Expected: public static bool {callbackMethod}(object msg)");

var parameter = Expression.Parameter(typeof(object));
var call = Expression.Call(null, method, parameter);
var predicate = Expression.Lambda<Func<object, bool>>(call, parameter).Compile();

return predicate;
}

static Func<object, bool> MesageTypeBased(Type actor, ReentrantAttribute[] attributes)
Expand Down

0 comments on commit 35c8115

Please sign in to comment.