in src/Microsoft.ServiceFabric.Actors/Runtime/ActorManager.cs [475:627]
public async Task DeleteActorAsync(string callContext, ActorId actorId, CancellationToken cancellationToken)
{
ExceptionDispatchInfo exceptionInfo = null;
if (!this.HasRemindersLoaded)
{
throw new ReminderLoadInProgressException(string.Format(
CultureInfo.CurrentCulture,
SR.DeleteActorConflictWithLoadReminders,
actorId));
}
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Delete call received for actor {0}",
actorId);
// Use ActorConcurrencyLock to synchronize with other actor calls.
// If the Actor is active, its ActorConcurrencyLock is used for synchronization.
// If the actor is inactive, a Dummy Actor instance is created and its ActorConcurrencyLock is used for synchronization.
using (
var actorUseScope = this.GetActor(
actorId: actorId,
createIfRequired: true,
timerCall: false,
createDummyActor: true))
{
var actor = actorUseScope.Actor;
await
actor.ConcurrencyLock.Acquire(
callContext,
(async innerActor => await this.HandleDirtyStateAsync(innerActor)),
ActorReentrancyMode.Disallowed,
cancellationToken);
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Acquired ReentrancyGuard for actor {0}.",
actorId);
// If Actor is already marked for deletion by other delete call, do not try to delete it again.
if (actor.MarkedForDeletion)
{
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Actor {0} is already marked for deletion, returning without processing this delete call.",
actorId);
}
else
{
try
{
this.ThrowIfClosed();
cancellationToken.ThrowIfCancellationRequested();
actor.MarkedForDeletion = true;
// Remove actor state(and reminders) first and then unregister reminders as RemoveActorState can throw
// and in this case reminders should not be unregistered.
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Removing actor state and reminders for Actor {0}.",
actor.Id);
await this.StateProvider.RemoveActorAsync(actorId, cancellationToken);
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Unregistering all reminders for Actor {0}.",
actor.Id);
if (this.remindersByActorId.TryGetValue(actorId, out var actorReminders))
{
var reminderNames = actorReminders.Values.Select(r => r.Name).ToList().AsReadOnly();
foreach (var reminderName in reminderNames)
{
await this.UnregisterReminderAsync(reminderName, actor.Id, false);
}
}
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Clearing event subscriptions for actor {0}.",
actorId);
await this.eventManager.ClearAllSubscriptions(actorId);
}
catch (Exception e)
{
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Removing state for actor {0} caused exception {1}, {2}.",
actorId,
e.Message,
e.StackTrace);
exceptionInfo = ExceptionDispatchInfo.Capture(e);
}
try
{
// deactivate must happen outside of above try catch to avoid scenarios
// in which Remove actor state and reminder from state provider throws.
if (this.activeActors.TryRemove(actorId, out var removedActor))
{
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Deactivating actor {0}",
actorId);
await this.DeactivateActorAsync(removedActor);
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Completed Deactivation of actor {0}",
actorId);
}
}
catch (Exception e)
{
// Catch exception as ReentrantGuard must be released.
ActorTrace.Source.WriteInfoWithId(
TraceType,
this.traceId,
"DeleteActorAsync: Deactivating actor {0} caused exception {1}, {2}.",
actorId,
e.Message,
e.StackTrace);
exceptionInfo = ExceptionDispatchInfo.Capture(e);
}
}
await actor.ConcurrencyLock.ReleaseContext(callContext);
if (exceptionInfo != null)
{
exceptionInfo.Throw();
}
return;
}
}