RegisterWritableEndpoint() public method

public RegisterWritableEndpoint ( Akka.Actor.Address address, IActorRef endpoint, int uid, int refuseUid ) : IActorRef
address Akka.Actor.Address
endpoint IActorRef
uid int
refuseUid int
return IActorRef
Ejemplo n.º 1
0
        protected void Accepting(object message)
        {
            message.Match()
            .With <ManagementCommand>(mc =>
            {
                var allStatuses = _transportMapping.Values.Select(x => x.ManagementCommand(mc));
                Task.WhenAll(allStatuses)
                .ContinueWith(x => new ManagementCommandAck(x.Result.All(y => y)),
                              TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.AttachedToParent)
                .PipeTo(Self);
            })
            .With <Quarantine>(quarantine =>
            {
                //Stop writers
                if (endpoints.WritableEndpointWithPolicyFor(quarantine.RemoteAddress) is Pass)
                {
                    var pass = (Pass)endpoints.WritableEndpointWithPolicyFor(quarantine.RemoteAddress);
                    Context.Stop(pass.Endpoint);
                    if (!pass.Uid.HasValue)
                    {
                        log.Warning("Association to [{0}] with unknown UID is reported as quarantined, but " +
                                    "address cannot be quarantined without knowing the UID, gated instead for {0} ms",
                                    quarantine.RemoteAddress, settings.RetryGateClosedFor.TotalMilliseconds);
                        endpoints.MarkAsFailed(pass.Endpoint, Deadline.Now + settings.RetryGateClosedFor);
                    }
                }

                //Stop inbound read-only association
                var read = endpoints.ReadOnlyEndpointFor(quarantine.RemoteAddress);
                if (read != null)
                {
                    Context.Stop((InternalActorRef)read);
                }

                if (quarantine.Uid.HasValue)
                {
                    endpoints.MarkAsQuarantined(quarantine.RemoteAddress, quarantine.Uid.Value, Deadline.Now + settings.QuarantineDuration);
                    eventPublisher.NotifyListeners(new QuarantinedEvent(quarantine.RemoteAddress, quarantine.Uid.Value));
                }
            })
            .With <Send>(send =>
            {
                var recipientAddress = send.Recipient.Path.Address;
                Func <int?, ActorRef> createAndRegisterWritingEndpoint = refuseUid => endpoints.RegisterWritableEndpoint(recipientAddress,
                                                                                                                         CreateEndpoint(recipientAddress, send.Recipient.LocalAddressToUse,
                                                                                                                                        _transportMapping[send.Recipient.LocalAddressToUse], settings, writing: true,
                                                                                                                                        handleOption: null, refuseUid: refuseUid), refuseUid);

                endpoints.WritableEndpointWithPolicyFor(recipientAddress).Match()
                .With <Pass>(
                    pass =>
                {
                    pass.Endpoint.Tell(send);
                })
                .With <Gated>(gated =>
                {
                    if (gated.TimeOfRelease.IsOverdue)
                    {
                        createAndRegisterWritingEndpoint(null).Tell(send);
                    }
                    else
                    {
                        Context.System.DeadLetters.Tell(send);
                    }
                })
                .With <Quarantined>(quarantined =>
                {
                    // timeOfRelease is only used for garbage collection reasons, therefore it is ignored here. We still have
                    // the Quarantined tombstone and we know what UID we don't want to accept, so use it.
                    createAndRegisterWritingEndpoint((int)quarantined.Uid).Tell(send);
                })
                .Default(msg => createAndRegisterWritingEndpoint(null).Tell(send));
            })
            .With <InboundAssociation>(HandleInboundAssociation)
            .With <EndpointWriter.StoppedReading>(endpoint => AcceptPendingReader(endpoint.Writer))
            .With <Terminated>(terminated =>
            {
                AcceptPendingReader(terminated.ActorRef);
                endpoints.UnregisterEndpoint(terminated.ActorRef);
                HandleStashedInbound(terminated.ActorRef);
            })
            .With <EndpointWriter.TookOver>(tookover => RemovePendingReader(tookover.Writer, tookover.ProtocolHandle))
            .With <ReliableDeliverySupervisor.GotUid>(gotuid =>
            {
                endpoints.RegisterWritableEndpointUid(Sender, gotuid.Uid);
                HandleStashedInbound(Sender);
            })
            .With <Prune>(prune => endpoints.Prune())
            .With <ShutdownAndFlush>(shutdown =>
            {
                //Shutdown all endpoints and signal to Sender when ready (and whether all endpoints were shutdown gracefully)

                // The construction of the Task for shutdownStatus has to happen after the flushStatus future has been finished
                // so that endpoints are shut down before transports.
                var shutdownStatus = Task.WhenAll(endpoints.AllEndpoints.Select(
                                                      x => x.GracefulStop(settings.FlushWait, new EndpointWriter.FlushAndStop()))).ContinueWith(
                    result =>
                {
                    if (result.IsFaulted)
                    {
                        if (result.Exception != null)
                        {
                            result.Exception.Handle(e => true);
                        }
                        return(false);
                    }
                    return(result.Result.All(x => x));
                }, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.AttachedToParent);

                var flushStatus = Task.WhenAll(_transportMapping.Values.Select(x => x.Shutdown())).ContinueWith(
                    result =>
                {
                    if (result.IsFaulted)
                    {
                        if (result.Exception != null)
                        {
                            result.Exception.Handle(e => true);
                        }
                        return(false);
                    }
                    return(result.Result.All(x => x));
                }, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.AttachedToParent);

                Task.WhenAll(shutdownStatus, flushStatus)
                .ContinueWith(x => x.Result.All(y => y),
                              TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.AttachedToParent)
                .PipeTo(Sender);

                foreach (var handoff in pendingReadHandoffs.Values)
                {
                    handoff.Disassociate(DisassociateInfo.Shutdown);
                }

                //Ignore all other writes
                Context.Become(Flushing);
            });
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Message-processing behavior when the <see cref="EndpointManager"/> is able to accept
        /// inbound association requests.
        /// </summary>
        protected void Accepting()
        {
            Receive <ManagementCommand>(mc =>
            {
                /*
                 * applies a management command to all available transports.
                 *
                 * Useful for things like global restart
                 */
                var sender      = Sender;
                var allStatuses = _transportMapping.Values.Select(x => x.ManagementCommand(mc.Cmd));
                Task.WhenAll(allStatuses)
                .ContinueWith(x =>
                {
                    return(new ManagementCommandAck(x.Result.All(y => y)));
                }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)
                .PipeTo(sender);
            });

            Receive <Quarantine>(quarantine =>
            {
                //Stop writers
                var policy =
                    Tuple.Create(_endpoints.WritableEndpointWithPolicyFor(quarantine.RemoteAddress), quarantine.Uid);
                if (policy.Item1 is Pass && policy.Item2 == null)
                {
                    var endpoint = policy.Item1.AsInstanceOf <Pass>().Endpoint;
                    Context.Stop(endpoint);
                    _log.Warning("Association to [{0}] with unknown UID is reported as quarantined, but " +
                                 "address cannot be quarantined without knowing the UID, gating instead for {1} ms.", quarantine.RemoteAddress, _settings.RetryGateClosedFor.TotalMilliseconds);
                    _endpoints.MarkAsFailed(endpoint, Deadline.Now + _settings.RetryGateClosedFor);
                }
                else if (policy.Item1 is Pass && policy.Item2 != null)
                {
                    var pass = policy.Item1 as Pass;
                    if (pass.Uid == quarantine.Uid)
                    {
                        Context.Stop(pass.Endpoint);
                    }
                }
                else
                {
                    // Do nothing, because either:
                    // A: we don't know yet the UID of the writer, it will be checked against current quarantine state later
                    // B: we know the UID, but it does not match with the UID to be quarantined
                }

                // Stop inbound read-only associations
                var readPolicy = Tuple.Create(_endpoints.ReadOnlyEndpointFor(quarantine.RemoteAddress), quarantine.Uid);
                if (readPolicy.Item1?.Item1 != null && quarantine.Uid == null)
                {
                    Context.Stop(readPolicy.Item1.Item1);
                }
                else if (readPolicy.Item1?.Item1 != null && quarantine.Uid != null && readPolicy.Item1?.Item2 == quarantine.Uid)
                {
                    Context.Stop(readPolicy.Item1.Item1);
                }
                else
                {
                }        // nothing to stop

                Func <AkkaProtocolHandle, bool> matchesQuarantine = handle => handle.RemoteAddress.Equals(quarantine.RemoteAddress) &&
                                                                    quarantine.Uid == handle.HandshakeInfo.Uid;

                // Stop all matching pending read handoffs
                _pendingReadHandoffs = _pendingReadHandoffs.Where(x =>
                {
                    var drop = matchesQuarantine(x.Value);
                    // Side-effecting here
                    if (drop)
                    {
                        x.Value.Disassociate();
                        Context.Stop(x.Key);
                    }
                    return(!drop);
                }).ToDictionary(key => key.Key, value => value.Value);

                // Stop all matching stashed connections
                _stashedInbound = _stashedInbound.Select(x =>
                {
                    var associations = x.Value.Where(assoc =>
                    {
                        var handle = assoc.Association.AsInstanceOf <AkkaProtocolHandle>();
                        var drop   = matchesQuarantine(handle);
                        if (drop)
                        {
                            handle.Disassociate();
                        }
                        return(!drop);
                    }).ToList();
                    return(new KeyValuePair <IActorRef, List <InboundAssociation> >(x.Key, associations));
                }).ToDictionary(k => k.Key, v => v.Value);

                if (quarantine.Uid.HasValue)
                {
                    _endpoints.MarkAsQuarantined(quarantine.RemoteAddress, quarantine.Uid.Value, Deadline.Now + _settings.QuarantineDuration);
                    _eventPublisher.NotifyListeners(new QuarantinedEvent(quarantine.RemoteAddress, quarantine.Uid.Value));
                }
            });

            Receive <Send>(send =>
            {
                var recipientAddress = send.Recipient.Path.Address;
                Func <int?, IActorRef> createAndRegisterWritingEndpoint = refuseUid => _endpoints.RegisterWritableEndpoint(recipientAddress,
                                                                                                                           CreateEndpoint(recipientAddress, send.Recipient.LocalAddressToUse,
                                                                                                                                          _transportMapping[send.Recipient.LocalAddressToUse], _settings, writing: true,
                                                                                                                                          handleOption: null, refuseUid: refuseUid), uid: null, refuseUid: refuseUid);

                _endpoints.WritableEndpointWithPolicyFor(recipientAddress).Match()
                .With <Pass>(
                    pass =>
                {
                    pass.Endpoint.Tell(send);
                })
                .With <Gated>(gated =>
                {
                    if (gated.TimeOfRelease.IsOverdue)
                    {
                        createAndRegisterWritingEndpoint(null).Tell(send);
                    }
                    else
                    {
                        Context.System.DeadLetters.Tell(send);
                    }
                })
                .With <Quarantined>(quarantined =>
                {
                    // timeOfRelease is only used for garbage collection reasons, therefore it is ignored here. We still have
                    // the Quarantined tombstone and we know what UID we don't want to accept, so use it.
                    createAndRegisterWritingEndpoint(quarantined.Uid).Tell(send);
                })
                .Default(msg => createAndRegisterWritingEndpoint(null).Tell(send));
            });
            Receive <InboundAssociation>(ia => HandleInboundAssociation(ia, false));
            Receive <EndpointWriter.StoppedReading>(endpoint => AcceptPendingReader(endpoint.Writer));
            Receive <Terminated>(terminated =>
            {
                AcceptPendingReader(terminated.ActorRef);
                _endpoints.UnregisterEndpoint(terminated.ActorRef);
                HandleStashedInbound(terminated.ActorRef, writerIsIdle: false);
            });
            Receive <EndpointWriter.TookOver>(tookover => RemovePendingReader(tookover.Writer, tookover.ProtocolHandle));
            Receive <ReliableDeliverySupervisor.GotUid>(gotuid =>
            {
                _endpoints.RegisterWritableEndpointUid(Sender, gotuid.Uid);
                HandleStashedInbound(Sender, writerIsIdle: false);
            });
            Receive <ReliableDeliverySupervisor.Idle>(idle =>
            {
                HandleStashedInbound(Sender, writerIsIdle: true);
            });
            Receive <Prune>(prune => _endpoints.Prune());
            Receive <ShutdownAndFlush>(shutdown =>
            {
                //Shutdown all endpoints and signal to Sender when ready (and whether all endpoints were shutdown gracefully)
                var sender = Sender;

                // The construction of the Task for shutdownStatus has to happen after the flushStatus future has been finished
                // so that endpoints are shut down before transports.
                var shutdownStatus = Task.WhenAll(_endpoints.AllEndpoints.Select(
                                                      x => x.GracefulStop(_settings.FlushWait, EndpointWriter.FlushAndStop.Instance))).ContinueWith(
                    result =>
                {
                    if (result.IsFaulted || result.IsCanceled)
                    {
                        if (result.Exception != null)
                        {
                            result.Exception.Handle(e => true);
                        }
                        return(false);
                    }
                    return(result.Result.All(x => x));
                }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                shutdownStatus.ContinueWith(tr => Task.WhenAll(_transportMapping.Values.Select(x => x.Shutdown())).ContinueWith(
                                                result =>
                {
                    if (result.IsFaulted || result.IsCanceled)
                    {
                        if (result.Exception != null)
                        {
                            result.Exception.Handle(e => true);
                        }
                        return(false);
                    }
                    return(result.Result.All(x => x) && tr.Result);
                }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)).Unwrap().PipeTo(sender);


                foreach (var handoff in _pendingReadHandoffs.Values)
                {
                    handoff.Disassociate(DisassociateInfo.Shutdown);
                }

                //Ignore all other writes
                _normalShutdown = true;
                Become(Flushing);
            });
        }