/// <summary> /// Dispatches a <see cref="SystemMessage"/> from a mailbox to an <see cref="ActorCell"/> /// </summary> public virtual void SystemDispatch(ActorCell cell, SystemMessage message) { var mbox = cell.Mailbox; mbox.SystemEnqueue(cell.Self, message); RegisterForExecution(mbox, false, true); }
/// <summary> /// Dispatches a user-defined message from a mailbox to an <see cref="ActorCell"/> /// </summary> public virtual void Dispatch(ActorCell cell, Envelope envelope) { var mbox = cell.Mailbox; mbox.Enqueue(cell.Self, envelope); RegisterForExecution(mbox, true, false); }
/// <summary> /// INTERNAL API /// /// If you override it, you must still call the base method. But only ever once. See <see cref="Attach"/> for only invocation. /// </summary> /// <param name="actor">The actor we're registering</param> internal virtual void Register(ActorCell actor) { if (DebugDispatcher) { Actors.Value.Put(this, (IInternalActorRef)actor.Self); } AddInhabitants(1); }
/// <summary> /// TBD /// </summary> /// <returns>TBD</returns> protected override ActorCell NewCell() { ActorCell cell = Props.RouterConfig is Pool pool && pool.Resizer != null ? new ResizablePoolCell(System, this, Props, Dispatcher, _routeeProps, Supervisor, pool) : new RoutedActorCell(System, this, Props, Dispatcher, _routeeProps, Supervisor); cell.Init(false, MailboxType); return(cell); }
/// <summary> /// After the call to this method, the dispatcher mustn't begin any new message processing for the specified reference /// </summary> /// <param name="actorCell">The cell of the actor whose mailbox will be suspended.</param> internal virtual void Suspend(ActorCell actorCell) { var mbox = actorCell.Mailbox; if (mbox.Actor == actorCell && mbox.Dispatcher == this) //make sure everything is referring to the same instance { mbox.Suspend(); } }
/// <summary> /// After the call to this method, the dispatcher must begin any new message processing for the specified reference /// </summary> /// <param name="actorCell">The cell of the actor whose mailbox will be resumed.</param> internal virtual void Resume(ActorCell actorCell) { var mbox = actorCell.Mailbox; if (mbox.Actor == actorCell && mbox.Dispatcher == this && mbox.Resume()) //make sure everything is referring to the same instance { RegisterForExecution(mbox, false, false); // force the mailbox to re-run after resume } }
public override void Attach(ActorCell cell) { if (cell.Props.Type == typeof(FastActor)) { _latch = cell.Props.Arguments[0] as TestLatch; } base.Attach(cell); }
/// <summary> /// TBD /// </summary> /// <param name="actor">TBD</param> /// <exception cref="InvalidOperationException"> /// This exception is thrown if the registering <paramref name="actor"/> is not the <see cref="_owner">owner</see>. /// </exception> internal override void Register(ActorCell actor) { var current = _owner; if (current != null && actor != current) { throw new InvalidOperationException($"Cannot register to anyone but {_owner}"); } _owner = actor; base.Register(actor); }
/// <summary> /// Detaches the dispatcher to the <see cref="ActorCell"/> /// /// <remarks> /// Only really used in dispatchers with 1:1 relationship with dispatcher. /// </remarks> /// </summary> /// <param name="cell">The ActorCell belonging to the actor who's detaching from this dispatcher.</param> public virtual void Detach(ActorCell cell) { try { Unregister(cell); } finally { IfSensibleToDoSoThenScheduleShutdown(); } }
/// <summary> /// INTERNAL API /// /// If you override it, you must call it. But only ever once. See <see cref="Detach"/> for the only invocation /// </summary> /// <param name="actor">The actor who is unregistering</param> internal virtual void Unregister(ActorCell actor) { if (DebugDispatcher) { Actors.Value.Remove(this, (IInternalActorRef)actor.Self); } AddInhabitants(-1); var mailbox = actor.SwapMailbox(Mailboxes.DeadLetterMailbox); mailbox.BecomeClosed(); mailbox.CleanUp(); }
private IInternalActorRef GetChild(string name) { var nameAndUid = ActorCell.SplitNameAndUid(name); IInternalActorRef child; if (TryGetChild(nameAndUid.Name, out child)) { if (nameAndUid.Uid != ActorCell.UndefinedUid && nameAndUid.Uid != child.Path.Uid) { return(ActorRefs.Nobody); } } return(child); }
public void Notify(NotificationMessage notificationMessage) { var notificationId = ++_lastNotificationId; if (notificationId <= 0) { notificationId = _lastNotificationId = 1; } notificationMessage.NotificationId = notificationId; var sender = ActorCell.GetCurrentSelfOrNoSender(); Receiver.Tell(notificationMessage, sender); }
/// <summary> /// Request a connection to the local docker API. /// </summary> /// <param name="dockerApi"> /// The Docker API extension for Akka.NET. /// </param> /// <param name="replyTo"> /// The actor to which the reply will be sent. /// </param> /// <param name="correlationId"> /// A message correlation Id that will be returned with the response. /// </param> /// <remarks> /// If successful, a reference to the <see cref="Client"/> actor will be delivered via a <see cref="Connected"/> message. /// Otherwise, a <see cref="ConnectFailed"/> message will be delivered. /// </remarks> public static void RequestConnectLocal(this DockerApi dockerApi, IActorRef replyTo = null, string correlationId = null) { if (dockerApi == null) { throw new ArgumentNullException(nameof(dockerApi)); } replyTo = replyTo ?? ActorCell.GetCurrentSenderOrNoSender(); if (replyTo.IsNobody()) { throw new InvalidOperationException("Cannot determine the actor to receive the reply."); } dockerApi.Manager.Tell( Connect.Local(correlationId), sender: replyTo ); }
/// <summary> /// TBD /// </summary> /// <returns>TBD</returns> protected override ActorCell NewCell() { var pool = Props.RouterConfig as Pool; ActorCell cell = null; if (pool != null) { if (pool.Resizer != null) { cell = new ResizablePoolCell(System, this, Props, Dispatcher, _routeeProps, Supervisor, pool); } } if (cell == null) { cell = new RoutedActorCell(System, this, Props, Dispatcher, _routeeProps, Supervisor); } cell.Init(false, MailboxType); return(cell); }
public SynergyPersistenceStashRabbitMq(IActorContext context, List <KeyValuePair <string, string> > config) { _actorCell = (ActorCell)context; _context = context; BootstrapServers = config.First(kvp => kvp.Key == "bootstrapserver").Value; Topic = config.First(kvp => kvp.Key == "topic").Value; _factory = new ConnectionFactory() { HostName = this.BootstrapServers }; _connection = _factory.CreateConnection(); _model = _connection.CreateModel(); _model.ExchangeDeclare(this.Topic, ExchangeType.Direct); _model.QueueDeclare(queue: this.Topic, durable: false, exclusive: false, autoDelete: false, arguments: null); _model.QueueBind(this.Topic, this.Topic, "directexchange_key"); }
protected override ActorCell NewCell() { var pool = _routerProps.RouterConfig as Pool; ActorCell cell = null; if (pool != null) { if (pool.Resizer != null) { //if there is a resizer, use ResizablePoolCell cell = new ResizablePoolCell(_system, this, _routerProps, _routerDispatcher, _routeeProps, _supervisor, pool); } } if (cell == null) { cell = new RoutedActorCell(_system, this, _routerProps, _routerDispatcher, _routeeProps, _supervisor); } cell.Init(sendSupervise: false, createMailbox: _createMailbox); return(cell); }
/// <summary>INTERNAL /// Abstract base class for stash support /// <remarks>Note! Part of internal API. Breaking changes may occur without notice. Use at own risk.</remarks> /// </summary> /// <exception cref="NotSupportedException">This exception is thrown if the actor's mailbox isn't deque-based (e.g. <see cref="UnboundedDequeBasedMailbox"/>).</exception> protected AbstractStash(IActorContext context, int capacity = 100) { var actorCell = (ActorCell)context; Mailbox = actorCell.Mailbox.MessageQueue as IDequeBasedMessageQueueSemantics; if(Mailbox == null) { string message = $@"DequeBasedMailbox required, got: {actorCell.Mailbox.GetType().Name} An (unbounded) deque-based mailbox can be configured as follows: my-custom-mailbox {{ mailbox-type = ""Akka.Dispatch.UnboundedDequeBasedMailbox"" }}"; throw new NotSupportedException(message); } _theStash = new LinkedList<Envelope>(); _actorCell = actorCell; // TODO: capacity needs to come from dispatcher or mailbox config // https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/actor/Stash.scala#L126 _capacity = capacity; }
/// <summary>INTERNAL /// Abstract base class for stash support /// <remarks>Note! Part of internal API. Breaking changes may occur without notice. Use at own risk.</remarks> /// </summary> protected AbstractStash(IActorContext context, int capacity = 100) { var actorCell = (ActorCell)context; var mailbox = actorCell.Mailbox as IDequeBasedMailbox; if (mailbox == null) { string message = @"DequeBasedMailbox required, got: " + actorCell.Mailbox.GetType().Name + @" An (unbounded) deque-based mailbox can be configured as follows: my-custom-mailbox { mailbox-type = ""Akka.Dispatch.UnboundedDequeBasedMailbox"" }"; throw new NotSupportedException(message); } _theStash = new LinkedList <Envelope>(); _actorCell = actorCell; // TODO: capacity needs to come from dispatcher or mailbox config // https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/actor/Stash.scala#L126 _capacity = capacity; }
public override ActorRef ResolveActorRef(ActorPath actorPath) { if (HasAddress(actorPath.Address)) { if (actorPath.Elements.Head() == "remote") { if (actorPath.ToStringWithoutAddress() == "/remote") { return(RemoteDaemon); } //skip ""/"remote", string[] parts = actorPath.Elements.Drop(1).ToArray(); return(RemoteDaemon.GetChild(parts)); } if (actorPath.Elements.Head() == "temp") { //skip ""/"temp", string[] parts = actorPath.Elements.Drop(1).ToArray(); return(TempContainer.GetChild(parts)); } //standard ActorCell currentContext = RootCell; if (actorPath.ToStringWithoutAddress() == "/") { return(currentContext.Self); } foreach (string part in actorPath.Elements) { currentContext = ((LocalActorRef)currentContext.Child(part)).Cell; } return(currentContext.Self); } return(new RemoteActorRef(Transport, Transport.LocalAddressForRemote(actorPath.Address), actorPath, ActorRef.Nobody, Props.None, Deploy.None)); }
public void Durable_CRDT_should_be_durable_after_gossip_update() { var r = NewReplicator(); RunOn(() => { Log.Debug("sending message with sender: {}", ActorCell.GetCurrentSelfOrNoSender()); r.Tell(Dsl.Update(_keyC, ORSet <string> .Empty, WriteLocal.Instance, c => c.Add(_cluster, Myself.Name))); ExpectMsg(new UpdateSuccess(_keyC, null)); }, _first); RunOn(() => { r.Tell(Dsl.Subscribe(_keyC, TestActor)); ExpectMsg <Changed>().Get(_keyC).Elements.ShouldBe(ImmutableHashSet.Create(_first.Name)); // must do one more roundtrip to be sure that it keyB is stored, since Changed might have // been sent out before storage TellUpdate(r, _keyA, WriteLocal.Instance, new PocoObject("Id_1", 3)); ExpectMsg(new UpdateSuccess(_keyA, null)); Watch(r); Sys.Stop(r); ExpectTerminated(r); var r2 = default(IActorRef); AwaitAssert(() => r2 = NewReplicator()); // try until name is free AwaitAssert(() => { r2.Tell(Dsl.GetKeyIds); ExpectMsg <GetKeysIdsResult>().Keys.ShouldNotBe(ImmutableHashSet <string> .Empty); }); r2.Tell(Dsl.Get(_keyC, ReadLocal.Instance)); ExpectMsg <GetSuccess>().Get(_keyC).Elements.ShouldBe(ImmutableHashSet.Create(_first.Name)); }, _second); EnterBarrierAfterTestStep(); }
/// <summary> /// Detaches the dispatcher to the <see cref="ActorCell"/> /// /// <remarks> /// Only really used in dispatchers with 1:1 relationship with dispatcher. /// </remarks> /// </summary> /// <param name="cell">The ActorCell belonging to the actor who's deatching from this dispatcher.</param> public virtual void Detach(ActorCell cell) { }
/// <summary> /// Dispatches a <see cref="ISystemMessage"/> from a mailbox to an <see cref="ActorCell"/> /// </summary> public virtual void SystemDispatch(ActorCell cell, Envelope envelope) { cell.SystemInvoke(envelope); }
/// <summary> /// Dispatches a user-defined message from a mailbox to an <see cref="ActorCell"/> /// </summary> public virtual void Dispatch(ActorCell cell, Envelope envelope) { cell.Invoke(envelope); }
/// <summary> /// Attaches an ActorCell to the Mailbox. /// </summary> /// <param name="actorCell"></param> public void SetActor(ActorCell actorCell) { _actorCell = actorCell; }
internal ActorTaskScheduler(ActorCell actorCell) { _actorCell = actorCell; }
/// <summary> /// Attaches the dispatcher to the <see cref="ActorCell"/> /// /// <remarks> /// Practically, doesn't do very much right now - dispatchers aren't responsible for creating /// mailboxes in Akka.NET /// </remarks> /// </summary> /// <param name="cell">The ActorCell belonging to the actor who's attaching to this dispatcher.</param> public virtual void Attach(ActorCell cell) { Register(cell); RegisterForExecution(cell.Mailbox, false, true); }
/// <summary> /// Creates and returns a <see cref="Mailbox"/> for the given actor. /// </summary> /// <param name="cell">Cell of the actor.</param> /// <param name="mailboxType">The mailbox configurator.</param> /// <returns>The configured <see cref="Mailbox"/> for this actor.</returns> internal Mailbox CreateMailbox(ActorCell cell, MailboxType mailboxType) { return(new Mailbox(mailboxType.Create(cell.Self, cell.System))); }
private void Run() { if (_isClosed) { return; } var throughputDeadlineTime = dispatcher.ThroughputDeadlineTime; ActorCell.UseThreadContext(() => { //if ThroughputDeadlineTime is enabled, start a stopwatch if (throughputDeadlineTime.HasValue && throughputDeadlineTime.Value > 0) { if (_deadLineTimer != null) { _deadLineTimer.Restart(); } else { _deadLineTimer = Stopwatch.StartNew(); } } //we are about to process all enqueued messages hasUnscheduledMessages = false; Envelope envelope; //start with system messages, they have the highest priority while (_systemMessages.TryDequeue(out envelope)) { Mailbox.DebugPrint(ActorCell.Self + " processing system message " + envelope); // TODO: Add + " with " + ActorCell.GetChildren()); dispatcher.SystemDispatch(ActorCell, envelope); } //we should process x messages in this run var left = dispatcher.Throughput; //try dequeue a user message while (!IsSuspended && !_isClosed && _userMessages.TryDequeue(out envelope)) { Mailbox.DebugPrint(ActorCell.Self + " processing message " + envelope); //run the receive handler dispatcher.Dispatch(ActorCell, envelope); //check if any system message have arrived while processing user messages if (_systemMessages.TryDequeue(out envelope)) { //handle system message Mailbox.DebugPrint(ActorCell.Self + " processing system message " + envelope); // TODO: Add + " with " + ActorCell.GetChildren()); dispatcher.SystemDispatch(ActorCell, envelope); break; } left--; if (_isClosed) { return; } //if deadline time have expired, stop and break if (throughputDeadlineTime.HasValue && throughputDeadlineTime.Value > 0 && _deadLineTimer.Elapsed.Ticks > throughputDeadlineTime.Value) { _deadLineTimer.Stop(); break; } //we are done processing messages for this run if (left == 0) { break; } } Interlocked.Exchange(ref status, MailboxStatus.Idle); //there are still messages that needs to be processed if (_systemMessages.Count > 0 || (!IsSuspended && _userMessages.Count > 0)) { //we still need has unscheduled messages for external info. //e.g. repointable actor ref uses it //TODO: will this be enough for external parties to work? hasUnscheduledMessages = true; //this is subject of a race condition //but that doesn't matter, since if the above "if" misses //the "Post" that adds the new message will still schedule //this specific call is just to deal with existing messages //that wasn't scheduled due to dispatcher throughput being reached //or system messages arriving during user message processing Schedule(); } }); }
/// <summary> /// TBD /// </summary> /// <param name="actor">TBD</param> internal override void Unregister(ActorCell actor) { base.Unregister(actor); _owner = null; }
/// <summary> /// TBD /// </summary> /// <param name="cell">TBD</param> public ActorCellKeepingSynchronizationContext(ActorCell cell) { _cell = cell; }
/// <summary> /// Attaches an ActorCell to the Mailbox. /// </summary> /// <param name="actorCell">TBD</param> public virtual void SetActor(ActorCell actorCell) { _actor = actorCell; }