Skip to content

Commit

Permalink
review remarks addressed
Browse files Browse the repository at this point in the history
  • Loading branch information
zbynek001 committed May 9, 2019
1 parent 6b5b988 commit e5d1adf
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 78 deletions.
145 changes: 94 additions & 51 deletions src/core/Akka.Tests/Actor/TimerSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,145 +46,145 @@ public AbstractTimerSpec()
public void Must_schedule_non_repeated_ticks()
{
var probe = CreateTestProbe();
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, TimeSpan.FromMilliseconds(10), false));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, TimeSpan.FromMilliseconds(10), false));

probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg(new Tock(1));
probe.ExpectNoMsg(100);

_ref.Tell(End.Instance);
probe.ExpectMsg<GotPostStop>(m => m.TimerActive == false);
actor.Tell(End.Instance);
probe.ExpectMsg(new GotPostStop(false));
}

[Fact]
public void Must_schedule_repeated_ticks()
{
var probe = CreateTestProbe();
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));

probe.Within(TimeSpan.FromSeconds(interval * 4) - TimeSpan.FromMilliseconds(100), () =>
{
probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg(new Tock(1));
probe.ExpectMsg(new Tock(1));
probe.ExpectMsg(new Tock(1));
});

_ref.Tell(End.Instance);
probe.ExpectMsg<GotPostStop>(m => m.TimerActive == false);
actor.Tell(End.Instance);
probe.ExpectMsg(new GotPostStop(false));
}

[Fact]
public void Must_replace_timer()
{
var probe = CreateTestProbe();
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));

probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg(new Tock(1));

var latch = this.CreateTestLatch(1);
// next Tock(1) enqueued in mailboxed, but should be discarded because of new timer
_ref.Tell(new SlowThenBump(latch));
actor.Tell(new SlowThenBump(latch));
probe.ExpectNoMsg(TimeSpan.FromSeconds(interval) + TimeSpan.FromMilliseconds(100));
latch.CountDown();
probe.ExpectMsg<Tock>(m => m.N == 2);
probe.ExpectMsg(new Tock(2));

_ref.Tell(End.Instance);
probe.ExpectMsg<GotPostStop>(m => m.TimerActive == false);
actor.Tell(End.Instance);
probe.ExpectMsg(new GotPostStop(false));
}

[Fact]
public void Must_cancel_timer()
{
var probe = CreateTestProbe();
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));

probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg(new Tock(1));

_ref.Tell(Cancel.Instance);
actor.Tell(Cancel.Instance);
probe.ExpectNoMsg(dilatedInterval + TimeSpan.FromMilliseconds(100));

_ref.Tell(End.Instance);
probe.ExpectMsg<GotPostStop>(m => m.TimerActive == false);
actor.Tell(End.Instance);
probe.ExpectMsg(new GotPostStop(false));
}

[Fact]
public void Must_cancel_timers_when_restarted()
{
var probe = CreateTestProbe();
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));

_ref.Tell(new Throw(new Exc()));
probe.ExpectMsg<GotPreRestart>(m => m.TimerActive == false);
actor.Tell(new Throw(new Exc()));
probe.ExpectMsg(new GotPreRestart(false));

_ref.Tell(End.Instance);
probe.ExpectMsg<GotPostStop>(m => m.TimerActive == false);
actor.Tell(End.Instance);
probe.ExpectMsg(new GotPostStop(false));
}

[Fact]
public void Must_discard_timers_from_old_incarnation_after_restart_alt_1()
{
var probe = CreateTestProbe();
var startCounter = new AtomicCounter(0);
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true, () => startCounter.IncrementAndGet()));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true, () => startCounter.IncrementAndGet()));

probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg(new Tock(1));

var latch = this.CreateTestLatch(1);
// next Tock(1) is enqueued in mailbox, but should be discarded by new incarnation
_ref.Tell(new SlowThenThrow(latch, new Exc()));
actor.Tell(new SlowThenThrow(latch, new Exc()));
probe.ExpectNoMsg(TimeSpan.FromSeconds(interval) + TimeSpan.FromMilliseconds(100));
latch.CountDown();
probe.ExpectMsg<GotPreRestart>(m => m.TimerActive == false);
probe.ExpectMsg(new GotPreRestart(false));
probe.ExpectNoMsg(TimeSpan.FromSeconds(interval / 2));
probe.ExpectMsg<Tock>(m => m.N == 2); // this is from the startCounter increment
probe.ExpectMsg(new Tock(2)); // this is from the startCounter increment

_ref.Tell(End.Instance);
probe.ExpectMsg<GotPostStop>(m => m.TimerActive == false);
actor.Tell(End.Instance);
probe.ExpectMsg(new GotPostStop(false));
}

[Fact]
public void Must_discard_timers_from_old_incarnation_after_restart_alt_2()
{
var probe = CreateTestProbe();
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));

probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg(new Tock(1));
// change state so that we see that the restart starts over again
_ref.Tell(Bump.Instance);
actor.Tell(Bump.Instance);

probe.ExpectMsg<Tock>(m => m.N == 2);
probe.ExpectMsg(new Tock(2));

var latch = this.CreateTestLatch(1);
// next Tock(2) is enqueued in mailbox, but should be discarded by new incarnation
_ref.Tell(new SlowThenThrow(latch, new Exc()));
actor.Tell(new SlowThenThrow(latch, new Exc()));
probe.ExpectNoMsg(TimeSpan.FromSeconds(interval) + TimeSpan.FromMilliseconds(100));
latch.CountDown();
probe.ExpectMsg<GotPreRestart>(m => m.TimerActive == false);
probe.ExpectMsg<Tock>(m => m.N == 1);
probe.ExpectMsg(new GotPreRestart(false));
probe.ExpectMsg(new Tock(1));

_ref.Tell(End.Instance);
probe.ExpectMsg<GotPostStop>(m => m.TimerActive == false);
actor.Tell(End.Instance);
probe.ExpectMsg(new GotPostStop(false));
}

[Fact]
public void Must_cancel_timers_when_stopped()
{
var probe = CreateTestProbe();
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, dilatedInterval, true));

_ref.Tell(End.Instance);
probe.ExpectMsg<GotPostStop>(m => m.TimerActive == false);
actor.Tell(End.Instance);
probe.ExpectMsg(new GotPostStop(false));
}

[Fact]
public void Must_handle_AutoReceivedMessages_automatically()
{
var probe = CreateTestProbe();
var _ref = this.Sys.ActorOf(TargetProps(probe.Ref, TimeSpan.FromMilliseconds(10), false));
var actor = this.Sys.ActorOf(TargetProps(probe.Ref, TimeSpan.FromMilliseconds(10), false));

this.Watch(_ref);
_ref.Tell(AutoReceive.Instance);
this.Watch(actor);
actor.Tell(AutoReceive.Instance);

ExpectTerminated(_ref);
ExpectTerminated(actor);
}


Expand Down Expand Up @@ -284,7 +284,22 @@ public Tock(int n)
{
N = n;
}

public override int GetHashCode()
{
return N.GetHashCode();
}

public override bool Equals(object obj)
{
if (obj is Tock other)
{
return N.Equals(other.N);
}
return false;
}
}

internal class GotPostStop : IEvent
{
public bool TimerActive { get; }
Expand All @@ -293,6 +308,20 @@ public GotPostStop(bool timerActive)
{
TimerActive = timerActive;
}

public override int GetHashCode()
{
return TimerActive.GetHashCode();
}

public override bool Equals(object obj)
{
if (obj is GotPostStop other)
{
return TimerActive.Equals(other.TimerActive);
}
return false;
}
}

internal class GotPreRestart : IEvent
Expand All @@ -303,6 +332,20 @@ public GotPreRestart(bool timerActive)
{
TimerActive = timerActive;
}

public override int GetHashCode()
{
return TimerActive.GetHashCode();
}

public override bool Equals(object obj)
{
if (obj is GotPreRestart other)
{
return TimerActive.Equals(other.TimerActive);
}
return false;
}
}

internal class Exc : Exception
Expand Down Expand Up @@ -499,9 +542,9 @@ public void Timers_combined_with_stashing_should_work()

var probe = CreateTestProbe();
var actor = this.Sys.ActorOf(Props.Create(() => new ActorWithTimerAndStash(probe.Ref)));
probe.ExpectMsg<string>(m => m == "saw-scheduled");
probe.ExpectMsg("saw-scheduled");
actor.Tell(StopStashing.Instance);
probe.ExpectMsg<string>(m => m == "scheduled");
probe.ExpectMsg("scheduled");
}

#region actors
Expand Down
10 changes: 1 addition & 9 deletions src/core/Akka/Actor/ActorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,7 @@ protected static IActorContext Context
}

private Scheduler.TimerScheduler timers;
public Scheduler.ITimerScheduler Timers
{
get
{
if (timers == null)
timers = new Scheduler.TimerScheduler(Context);
return timers;
}
}
public Scheduler.ITimerScheduler Timers => timers ?? (timers = new Scheduler.TimerScheduler(Context));

/// <summary>
/// TBD
Expand Down
10 changes: 5 additions & 5 deletions src/core/Akka/Actor/Scheduler/ITimerScheduler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public interface ITimerScheduler
/// <param name="key">Name of timer</param>
/// <param name="msg">Message to schedule</param>
/// <param name="interval">Interval</param>
void StartPeriodicTimer(string key, object msg, TimeSpan interval);
void StartPeriodicTimer(object key, object msg, TimeSpan interval);

/// <summary>
/// Start a periodic timer that will send <paramref name="msg"/> to the "Self" actor at
Expand All @@ -44,7 +44,7 @@ public interface ITimerScheduler
/// <param name="msg">Message to schedule</param>
/// <param name="initialDelay">Initial delay</param>
/// <param name="interval">Interval</param>
void StartPeriodicTimer(string key, object msg, TimeSpan initialDelay, TimeSpan interval);
void StartPeriodicTimer(object key, object msg, TimeSpan initialDelay, TimeSpan interval);

/// <summary>
/// Start a timer that will send <paramref name="msg"/> once to the "Self" actor after
Expand All @@ -58,14 +58,14 @@ public interface ITimerScheduler
/// <param name="key">Name of timer</param>
/// <param name="msg">Message to schedule</param>
/// <param name="timeout">Interval</param>
void StartSingleTimer(string key, object msg, TimeSpan timeout);
void StartSingleTimer(object key, object msg, TimeSpan timeout);

/// <summary>
/// Check if a timer with a given <paramref name="key"/> is active.
/// </summary>
/// <param name="key"></param>
/// <returns>Name of timer</returns>
bool IsTimerActive(string key);
bool IsTimerActive(object key);

/// <summary>
/// Cancel a timer with a given <paramref name="key"/>.
Expand All @@ -77,7 +77,7 @@ public interface ITimerScheduler
/// be enqueued in the mailbox when cancel is called.
/// </summary>
/// <param name="key">Name of timer</param>
void Cancel(string key);
void Cancel(object key);

/// <summary>
/// Cancel all timers.
Expand Down
Loading

0 comments on commit e5d1adf

Please sign in to comment.