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);
});
}