void Terminate(AgentProcessState agentProcessState) { lock (runningAgentProcessStateLock) { agentProcessState.AgentProcess.UnexpectedlyTerminated -= HandleAgentProcessUnexpectedlyTerminated; if (runningAgentProcessState == agentProcessState) { runningAgentProcessState = null; } } AgentProcessTicket [] copiedTickets; lock (tickets) { copiedTickets = tickets.ToArray(); tickets.Clear(); } MainThread.Post(() => { foreach (var ticket in copiedTickets) { try { ticket.NotifyDisconnected(); } catch (Exception e) { Log.Error(TAG, "exception when notifying ticket of disconnect", e); } } }); // Always run this as a form of disposal, because new AgentProcesses are created on-demand. // AgentProcess implementations should not let their Terminate implementations throw. agentProcessState.AgentProcess.TerminateAgentProcessAsync().Forget(); }
async Task MonitorConnectionAsync(AgentProcessState agentProcessState) { // NOTE: we do not pass the cancellation token for the // ticket since the AgentClient may outlive the ticket try { await agentProcessState .AgentClient .OpenAgentMessageChannel(default(CancellationToken)) .ConfigureAwait(false); } finally { HandleAgentProcessUnexpectedlyTerminated( agentProcessState?.AgentProcess, EventArgs.Empty); } }
public async Task <IAgentProcessState> StartAsync( AgentProcessTicket ticket, CancellationToken cancellationToken) { if (ticket == null) { throw new ArgumentNullException(nameof(ticket)); } if (ticket.IsDisposed) { throw new ObjectDisposedException(nameof(ticket)); } try { LogStartStatus(ticket, "waiting for all clear"); await startWait.WaitAsync().ConfigureAwait(false); AgentProcessState agentProcessState; lock (runningAgentProcessStateLock) { if (runningAgentProcessState != null) { LogStartStatus(ticket, "using existing agent process manager"); RegisterTicket(ticket); return(runningAgentProcessState); } } LogStartStatus(ticket, "creating new agent process manager"); agentProcessState = new AgentProcessState(workbookApp, agentProcessType); agentProcessState.AgentProcess.UnexpectedlyTerminated += HandleAgentProcessUnexpectedlyTerminated; var identifyAgentRequest = ClientApp .SharedInstance .WebServer .AgentIdentificationManager .GetAgentIdentityRequest(cancellationToken); LogStartStatus(ticket, "waiting for agent process manager to start"); await agentProcessState.AgentProcess.StartAgentProcessAsync( identifyAgentRequest, ticket.MessageService, cancellationToken).ConfigureAwait(false); LogStartStatus(ticket, "requesting agent identity"); agentProcessState.AgentIdentity = await ClientApp .SharedInstance .WebServer .AgentIdentificationManager .GetAgentIdentityAsync(identifyAgentRequest).ConfigureAwait(false); var agentAssociable = agentProcessState.AgentProcess as IAgentAssociable; if (agentAssociable == null) { LogStartStatus(ticket, "creating agent client"); agentProcessState.AgentClient = new AgentClient( agentProcessState.AgentIdentity.Host, agentProcessState.AgentIdentity.Port); } else { LogStartStatus(ticket, "waiting on agent association"); var agentAssociation = await agentAssociable.GetAgentAssociationAsync( agentProcessState.AgentIdentity, cancellationToken).ConfigureAwait(false); agentProcessState.AgentIdentity = agentAssociation.Identity; agentProcessState.AgentClient = agentAssociation.Client; } try { LogStartStatus(ticket, "registering ticket"); RegisterTicket(ticket); } catch (ObjectDisposedException e) { Terminate(agentProcessState); throw e; } lock (runningAgentProcessStateLock) runningAgentProcessState = agentProcessState; MonitorConnectionAsync(agentProcessState).Forget(); return(agentProcessState); } catch (Exception e) { Log.Error(TAG, nameof(StartAsync), e); throw e; } finally { startWait.Release(); } }