static ActorAssignment GetAssignment(Actor actor, bool prepareTestData = true) { ActorAssignment actorEntity = null; try { // Create the CloudTable object that represents the "topology" table. CloudTable table = Environment.GetTable("topology"); // $TEST: prepare test data so that the code can be executed in Azure Emulator if (prepareTestData) { Environment.PrepareTestData(actor); } // Create a retrieve operation that takes a customer entity. TableOperation retrieveOperation = TableOperation.Retrieve <ActorAssignment>(ActorAssignment.Key, actor.Id.ToString()); // Execute the retrieve operation. TableResult retrievedResult = table.Execute(retrieveOperation); // Get Assignment if (retrievedResult.Result != null) { actorEntity = (ActorAssignment)retrievedResult.Result; } } catch (Exception e) { Trace.TraceInformation("Failed to get assignment:" + e.Message); RoundLogger.Current.Log(e.StackTrace); } return(actorEntity); }
// The thread procedure performs the independent task static void ThreadProc(Object stateInfo) { ActorAssignment assignment = null; Actor actor = (Actor)stateInfo; Trace.TraceInformation("Deployment {0} Actor {1} is Initialized.", actor.DeploymentId, actor.Id); while (true) { RoundLogger.Current.SetSceneId(actor); if (actor.State == ActorState.NewBorn) { // Needs to contact central to get new assignment // if there is an assignment then assignment = GetAssignment(actor); if (assignment != null && !string.IsNullOrWhiteSpace(assignment.Name)) { actor.State = ActorState.Working; RoundLogger.Current.Log("Get Assignment and switch State to Working."); } else { RoundLogger.Current.Log("Waiting for assignment."); // Let's check assignment 10 seconds later Thread.Sleep(10000); } } else if (actor.State == ActorState.Working) { RoundLogger.Current.Log("Working on the assignment"); try { // $TODO: need to fetch package for new assignment (new ActorExecution(actor, assignment)).Run(); } catch (Exception e) { actor.State = ActorState.Error; actor.ErrorMessage = e.Message; actor.ErrorStack = e.StackTrace; RoundLogger.Current.Log("Failed to execute topology:" + e.Message); RoundLogger.Current.Log(e.StackTrace); } } else if (actor.State == ActorState.Error) { RoundLogger.Current.Log("The Actor is shutdown due to Error State."); break; } actor.HeartBeat = DateTime.UtcNow; } }
public ActorExecution(Actor actor, ActorAssignment assignment) { this.actor = actor; this.assignment = assignment; }
/// <summary> /// - Send Heartbeat to Central /// - Service Up/Down /// - Actor State /// - Kill Error Actor and Keep Actor Number; /// </summary> internal void Run() { do { Thread.Sleep(15000); Trace.TraceInformation("Service Maintain {0}", RoleEnvironment.DeploymentId); CloudTable table = Environment.GetTable("topology"); lock (LockObject) { IList <Guid> errorActors = new List <Guid>(); // Remove Actor which in Error State, and fork a new one foreach (Guid id in this.actors.Keys) { // NOTE: we still give Actor in Error State the last chance to report its state. if (this.actors[id].State == ActorState.Error) { // Cannot modify this.actors in foreach errorActors.Add(id); } try { if (this.actors[id].State == ActorState.Working) { var ass = GetAssignment(this.actors[id], false); if (ass != null) { if (string.Equals("Kill", ass.Operation, StringComparison.OrdinalIgnoreCase)) { // I didn't lock this Actor considering there is no state transition from Working to non Error. this.actors[id].State = ActorState.Error; } } } ActorAssignment assignment = new ActorAssignment(id) { HeartBeat = this.actors[id].HeartBeat, State = this.actors[id].State.ToString(), ErrorMessage = this.actors[id].ErrorMessage, ErrorStack = this.actors[id].ErrorStack }; TableOperation mergeOperation = TableOperation.InsertOrMerge(assignment); TableResult retrievedResult = table.Execute(mergeOperation); Trace.TraceInformation("Actor {0} updated HeartBeat", id); } catch (Exception e) { Trace.TraceInformation("Actor {0} failed to update HeartBeat due to {1}", id, e.Message); } } foreach (Guid id in errorActors) { this.actors.Remove(id); this.ForkNewActor(); } } }while (true); }