private async ValueTask <IAppConnection> ResolveTargetConnectionAsync( IConsumedMethodReference method, IAppConnection source) { Log.Debug("Resolving target connection for call {{{0}}} from {{{1}}}", method, source); string appId; ResolveMode resolveMode; var targetMethods = _registryService.GetMatchingProvidedMethods(source.Info.ApplicationId, method); var onlineProvidedMethods = _appLifecycleManager .GetOnlineConnections() .Where(x => !x.Id.Equals(source.Id)) .Join( targetMethods.Where(x => GetLaunchMode(x) != LaunchMode.MultiInstance), x => x.Info.ApplicationId, y => y.ProvidedService.Application.Id, (x, y) => (Method: y, AppConnection: x)) .ToArray(); if (onlineProvidedMethods.Any()) { var connection = onlineProvidedMethods.First().AppConnection; Log.Debug("Resolved target connection for call {{{0}}} from {{{1}}} to online connection: {{{2}}}", method, source, connection); return(connection); } lock (_resolveConnectionSync) { Log.Debug("Resolving target connection for call {{{0}}} from {{{1}}} to offline connection", method, source); var appIds = _appLifecycleManager.FilterCanBeLaunched( targetMethods.Select(x => x.ProvidedService.Application.Id).Distinct()); targetMethods = targetMethods.Join(appIds, x => x.ProvidedService.Application.Id, y => y, (x, y) => x).ToArray(); var singleInstanceMethods = targetMethods .Where(x => GetLaunchMode(x) == LaunchMode.SingleInstance) .ToArray(); var candidate = singleInstanceMethods.FirstOrDefault(x => !x.ProvidedService.Application.Id.Equals(source.Info.ApplicationId)); resolveMode = ResolveMode.SingleInstance; if (candidate == null) { candidate = singleInstanceMethods.FirstOrDefault(); resolveMode = ResolveMode.SingleInstance; } if (candidate == null) { candidate = targetMethods.FirstOrDefault(x => GetLaunchMode(x) == LaunchMode.MultiInstance); resolveMode = ResolveMode.MultiInstance; } if (candidate == null) { throw new InvalidOperationException($"Cannot resolve target for invocation {{{method}}} from {{{source}}}"); } Log.Debug("Resolved target connection for call {{{0}}} from {{{1}}} to provided method {{{2}}}", method, source, candidate); appId = candidate.ProvidedService.Application.Id; } var resolvedConnection = await _appLifecycleManager .ResolveConnectionAsync(appId, resolveMode, source.Info) .ConfigureAwait(false); return(resolvedConnection.AppConnection); }
private IEnumerable <string> FilterAvailableApps(string[] providerApps) { var launchableProviderApps = _appLifecycleManager.FilterCanBeLaunched(providerApps); var onlineApps = _appLifecycleManager.GetOnlineConnections().Select(x => x.Info.ApplicationId).Distinct(); var onlineProviderApps = providerApps.Intersect(onlineApps); var availableProviderApps = launchableProviderApps.Union(onlineProviderApps); return(availableProviderApps); }
private async ValueTask <IAppConnection> ResolveTargetConnectionAsync( IConsumedMethodReference method, IAppConnection source, ITransportChannel sourceChannel, IContextLinkageOptions contextLinkageOptions) { Log.Debug("Resolving target connection for call {{{0}}} from {{{1}}} for {2} invocation", method, source, sourceChannel.Id); string appId; ResolveMode resolveMode; var targetMethods = _registryService.GetMatchingProvidedMethods(source.Info.ApplicationId, method); var onlineProvidedMethods = _appLifecycleManager .GetOnlineConnections() .Where(x => !x.Id.Equals(source.Id)) .Join( targetMethods.Where(x => GetLaunchMode(x) != LaunchMode.MultiInstance), x => x.Info.ApplicationId, y => y.ProvidedService.Application.Id, (x, y) => (Method: y, AppConnection: x)) .ToArray(); if (_contextLinkageManager.IsContextShouldBeConsidered(contextLinkageOptions, source)) { onlineProvidedMethods = _contextLinkageManager.GetAppsInContexts(contextLinkageOptions, source, true) .Join(onlineProvidedMethods, x => x.ConnectionId.Value, y => y.AppConnection.Id, (x, y) => y).ToArray(); } if (onlineProvidedMethods.Any()) { var connection = onlineProvidedMethods.First().AppConnection; Log.Debug("Resolved target connection for call {{{0}}} from {{{1}}} to online connection {{{2}}} for {3} invocation", method, source, connection, sourceChannel.Id); return(connection); } lock (_resolveConnectionSync) { Log.Debug("Resolving target connection for call {{{0}}} (invocation {2}) from {{{1}}} to offline connection", method, source, sourceChannel.Id); var appIds = _appLifecycleManager.FilterCanBeLaunched( targetMethods.Select(x => x.ProvidedService.Application.Id).Distinct()); targetMethods = targetMethods.Join(appIds, x => x.ProvidedService.Application.Id, y => y, (x, y) => x).ToArray(); var singleInstanceMethods = targetMethods.Where(x => GetLaunchMode(x) == LaunchMode.SingleInstance).ToArray(); var onlineConnections = new HashSet <string>(_appLifecycleManager.GetOnlineConnections().Select(connection => connection.Info.ApplicationId)); var candidate = singleInstanceMethods.FirstOrDefault(x => !x.ProvidedService.Application.Id.Equals(source.Info.ApplicationId) && !onlineConnections.Contains(x.ProvidedService.Application.Id)); resolveMode = ResolveMode.SingleInstance; if (candidate == null) { candidate = singleInstanceMethods.FirstOrDefault(x => !onlineConnections.Contains(x.ProvidedService.Application.Id)); resolveMode = ResolveMode.SingleInstance; } if (candidate == null) { candidate = targetMethods.FirstOrDefault(x => GetLaunchMode(x) == LaunchMode.MultiInstance); resolveMode = ResolveMode.MultiInstance; } if (candidate == null) { candidate = targetMethods.FirstOrDefault(x => GetLaunchMode(x) != LaunchMode.None); resolveMode = ResolveMode.MultiInstance; } if (candidate == null) { throw new InvalidOperationException($"Cannot resolve target for invocation {{{method}}} from {{{source}}} for {sourceChannel.Id} invocation"); } Log.Debug("Resolved target connection for call {{{0}}} from {{{1}}} to provided method {{{2}}} for {3} invocation", method, source, candidate, sourceChannel.Id); appId = candidate.ProvidedService.Application.Id; } var launchAppTask = _appLifecycleManager.LaunchAndConnectAsync(appId, resolveMode, source.Info); var completedTask = await Task.WhenAny(launchAppTask, source.IncomingChannels.Completion).ConfigureAwait(false); if (completedTask == launchAppTask) { var resolvedConnection = await launchAppTask.ConfigureAwait(false); return(resolvedConnection.AppConnection); } throw new TaskCanceledException($"Launch of application {appId} canceled because source connection {source.Info} is completed"); }