private async ValueTask <IAppConnection> ResolveTargetConnectionAsync( IProvidedMethodReference methodReference, IAppConnection source, IContextLinkageOptions contextLinkageOptions) { var method = _registryService.GetProvidedMethod(methodReference); var launchMode = GetLaunchMode(method); var appId = methodReference.ProvidedService.ApplicationId; if (methodReference.ProvidedService.ConnectionId.HasValue) { var connectionId = methodReference.ProvidedService.ConnectionId.Value; if (!_appLifecycleManager.TryGetOnlineConnection(connectionId, out var connection)) { throw new InvalidOperationException($"The requested app {appId} connection {connectionId} is not online"); } return(connection); } Task <ResolvedConnection> resolveTask; lock (_resolveConnectionSync) { if (launchMode != LaunchMode.MultiInstance) { var onlineConnections = _appLifecycleManager .GetOnlineConnections() .Where(x => x.Info.ApplicationId.Equals(appId) && !x.Id.Equals(source.Id)).ToArray(); if (_contextLinkageManager.IsContextShouldBeConsidered(contextLinkageOptions, source)) { onlineConnections = _contextLinkageManager .GetAppsInContexts(contextLinkageOptions, source, true) .Join(onlineConnections, x => x.ConnectionId.Value, y => y.Id, (x, y) => y) .ToArray(); } if (onlineConnections.Any()) { return(onlineConnections.First()); } } if (launchMode == LaunchMode.None || !_appLifecycleManager.CanBeLaunched(appId)) { throw new InvalidOperationException( $"The requested app {appId} is not online and cannot be launched"); } var resolveMode = ConvertToResolveMode(launchMode); resolveTask = _appLifecycleManager.LaunchAndConnectAsync(appId, resolveMode, source.Info); } var resolvedConnection = await resolveTask.ConfigureAwait(false); return(resolvedConnection.AppConnection); }
public async Task <ResolveAppResponse> ResolveApp(ResolveAppRequest request, MethodCallContext context) { Log.Info("Resolving app by request {{{0}}} from {{{1}}}", request, context); var referrerConnectionInfo = new AppConnectionDescriptor( context.ConsumerConnectionId, context.ConsumerApplicationId, context.ConsumerApplicationInstanceId, context.ConsumerTransportType); var resolveMode = Convert(request.AppResolveMode); if (resolveMode == ResolveMode.SingleInstance) { var connection = _appLifecycleManager.GetOnlineConnections().FirstOrDefault(c => c.Info.ApplicationId.Equals(request.AppId)); Log.Debug("Resolved connection for app {0} with mode {1} to online instance {{{2}}}", connection, resolveMode, connection); if (connection != null) { return(new ResolveAppResponse { AppInstanceId = connection.Info.ApplicationInstanceId.ToProto(), AppConnectionId = connection.Info.ConnectionId.ToProto(), IsNewInstanceLaunched = false, }); } } var resolvedConnection = await _appLifecycleManager.LaunchAndConnectAsync( request.AppId, resolveMode, referrerConnectionInfo).ConfigureAwait(false); var info = resolvedConnection.AppConnection.Info; Log.Info("App connection {{{0}}} resolved by request from {{{1}}}", resolvedConnection, context); var response = new ResolveAppResponse { AppConnectionId = info.ConnectionId.ToProto(), AppInstanceId = info.ApplicationInstanceId.ToProto(), IsNewInstanceLaunched = resolvedConnection.IsNewInstance }; return(response); }
public async Task HandleAsync( IServiceDiscoveryRequest request, IAppConnection sourceConnection, ITransportChannel sourceChannel) { IReadOnlyCollection <(IConsumedMethod Consumed, IProvidedMethod Provided)> methodMatches; if (request.ConsumedService.HasValue) { methodMatches = _registryService.GetMethodMatches( sourceConnection.Info.ApplicationId, request.ConsumedService.Value); } else { methodMatches = _registryService.GetMethodMatches(sourceConnection.Info.ApplicationId); } IEnumerable <IGrouping <(IConsumedService ConsumedService, IProvidedService ProvidedService, Maybe <UniqueId> ConnectionId), IProvidedMethod> > groupedMethods; if (request.DiscoveryMode == DiscoveryMode.Offline) { groupedMethods = methodMatches .GroupBy( x => ( x.Consumed.ConsumedService, x.Provided.ProvidedService, ConnectionId: Maybe <UniqueId> .Nothing), x => x.Provided); } else { var onlineConnections = _connectionTracker.GetOnlineConnections(); groupedMethods = methodMatches .Join(onlineConnections, x => x.Provided.ProvidedService.Application.Id, y => y.Info.ApplicationId, (x, y) => (Match: x, ConnectionId: y.Id)) .GroupBy( x => ( x.Match.Consumed.ConsumedService, x.Match.Provided.ProvidedService, new Maybe <UniqueId>(x.ConnectionId)), x => x.Match.Provided); } var discoveredServices = from s in groupedMethods let consumedService = s.Key.ConsumedService let providedService = s.Key.ProvidedService let connectionId = s.Key.ConnectionId select _protocol.MessageFactory.CreateDiscoveredService( _protocol.MessageFactory.CreateConsumedServiceReference( consumedService.Service.Id, consumedService.Alias), _protocol.MessageFactory.CreateProvidedServiceReference( providedService.Service.Id, providedService.Alias, providedService.Application.Id, connectionId), s.Key.ProvidedService.Title, s.Select(m => _protocol.MessageFactory.CreateDiscoveredServiceMethod( m.Method.Name, m.Title, m.Method.InputMessage.Id, m.Method.OutputMessage.Id, Convert(m.Method.Type))).ToList()); using (var response = _protocol.MessageFactory.CreateServiceDiscoveryResponse(discoveredServices.ToList())) { Log.Info("Completed service discovery request {{{0}}} from {{{1}}}: {2}", request, sourceConnection, response); var serializedResponse = _protocol.Serializer.Serialize(response); try { await sourceChannel.Out .WriteAsync(new TransportMessageFrame(serializedResponse)) .ConfigureAwait(false); } catch { serializedResponse.Dispose(); throw; } } }
private async ValueTask <IAppConnection> ResolveTargetConnectionAsync( IProvidedMethodReference methodReference, IAppConnection source, ITransportChannel sourceChannel, IContextLinkageOptions contextLinkageOptions) { if (methodReference.ProvidedService.ConnectionId.HasValue) { var connectionId = methodReference.ProvidedService.ConnectionId.Value; if (!_appLifecycleManager.TryGetOnlineConnection(connectionId, out var connection)) { throw new InvalidOperationException($"The requested connection {connectionId} is not online"); } return(connection); } var appId = methodReference.ProvidedService.ApplicationId; if (methodReference.ProvidedService.ApplicationInstanceId.HasValue) { var appInstanceId = methodReference.ProvidedService.ApplicationInstanceId.Value; if (appId.HasValue && _appLifecycleManager.TryGetConnectionInProgress(appInstanceId, appId.Value, out var connectionInProgress)) { return(await connectionInProgress); } var connections = _appLifecycleManager.GetAppInstanceConnections(appInstanceId).ToList(); if (connections.Count == 0) { throw new InvalidOperationException($"App instance {appInstanceId} is doesn't have online connections"); } if (appId.HasValue) { var connection = connections.FirstOrDefault(c => c.Info.ApplicationId.Equals(appId.Value)); if (connection == null) { throw new InvalidOperationException($"App instance {appInstanceId} is doesn't have connection with {appId.Value} application id"); } return(connection); } if (connections.Count == 1) { return(connections.Single()); } throw new InvalidOperationException($"App instance {appInstanceId} has several connections, you need to specify ApplicationId to make call to specific connection"); } if (!appId.HasValue) { throw new InvalidOperationException($"AppId is required to resolve target connection for {methodReference} provided method reference"); } var appIdValue = appId.Value; var method = _registryService.GetProvidedMethod(methodReference); var launchMode = GetLaunchMode(method); Task <ResolvedConnection> resolveTask; lock (_resolveConnectionSync) { if (launchMode != LaunchMode.MultiInstance) { var onlineConnections = _appLifecycleManager .GetOnlineConnections() .Where(x => x.Info.ApplicationId.Equals(appIdValue) && !x.Id.Equals(source.Id)).ToArray(); if (_contextLinkageManager.IsContextShouldBeConsidered(contextLinkageOptions, source)) { onlineConnections = _contextLinkageManager .GetAppsInContexts(contextLinkageOptions, source, true) .Join(onlineConnections, x => x.ConnectionId.Value, y => y.Id, (x, y) => y) .ToArray(); } if (onlineConnections.Any()) { return(onlineConnections.First()); } } if (launchMode == LaunchMode.None || !_appLifecycleManager.CanBeLaunched(appIdValue)) { throw new InvalidOperationException( $"The requested app {appIdValue} is not online and cannot be launched"); } var resolveMode = ConvertToResolveMode(launchMode); resolveTask = _appLifecycleManager.LaunchAndConnectAsync(appIdValue, resolveMode, source.Info); } var resolvedConnection = await resolveTask.ConfigureAwait(false); return(resolvedConnection.AppConnection); }
public async Task HandleAsync( IServiceDiscoveryRequest request, IAppConnection sourceConnection, ITransportChannel sourceChannel) { IReadOnlyCollection <(IConsumedMethod Consumed, IProvidedMethod Provided)> methodMatches; if (request.ConsumedService.HasValue) { methodMatches = _registryService.GetMethodMatches( sourceConnection.Info.ApplicationId, request.ConsumedService.Value); } else { methodMatches = _registryService.GetMethodMatches(sourceConnection.Info.ApplicationId); } IEnumerable <IGrouping <(IConsumedService ConsumedService, IProvidedService ProvidedService, Maybe <UniqueId> ConnectionId, Maybe <UniqueId> ApplicationInstanceId), IProvidedMethod> > groupedMethods; var online = request.DiscoveryMode == DiscoveryMode.Online; if (_contextLinkageManager.IsContextShouldBeConsidered(request.ContextLinkageOptions, sourceConnection)) { groupedMethods = _contextLinkageManager.GetAppsInContexts(request.ContextLinkageOptions, sourceConnection, online) .Join(methodMatches, x => x.AppId, y => y.Provided.ProvidedService.Service.Id, (x, y) => (y.Consumed, y.Provided, x.AppInstanceId, x.ConnectionId)) .GroupBy(x => (x.Consumed.ConsumedService, x.Provided.ProvidedService, x.ConnectionId, new Maybe <UniqueId>(x.AppInstanceId)), x => x.Provided); } else { if (online) { var onlineConnections = _appLifecycleManager.GetOnlineConnections(); groupedMethods = methodMatches .Join(onlineConnections, x => x.Provided.ProvidedService.Application.Id, y => y.Info.ApplicationId, (x, y) => (Match: x, ConnectionId: y.Id, y.Info.ApplicationInstanceId)) .GroupBy( x => ( x.Match.Consumed.ConsumedService, x.Match.Provided.ProvidedService, new Maybe <UniqueId>(x.ConnectionId), new Maybe <UniqueId>(x.ApplicationInstanceId)), x => x.Match.Provided); } else { var providerApps = methodMatches.Select(x => x.Provided.ProvidedService.Application.Id).Distinct() .ToArray(); var availableProviderApps = FilterAvailableApps(providerApps); groupedMethods = methodMatches .Join( availableProviderApps, x => x.Provided.ProvidedService.Application.Id, y => y, (x, y) => x) .GroupBy( x => ( x.Consumed.ConsumedService, x.Provided.ProvidedService, ConnectionId: Maybe <UniqueId> .Nothing, ApplicationInstanceId: Maybe <UniqueId> .Nothing), x => x.Provided); } } var discoveredServices = from s in groupedMethods let consumedService = s.Key.ConsumedService let providedService = s.Key.ProvidedService let connectionId = s.Key.ConnectionId let applicationInstanceId = s.Key.ApplicationInstanceId select _protocol.MessageFactory.CreateDiscoveredService( _protocol.MessageFactory.CreateConsumedServiceReference( consumedService.Service.Id, consumedService.Alias), _protocol.MessageFactory.CreateProvidedServiceReference( providedService.Service.Id, providedService.Alias, providedService.Application.Id, connectionId, applicationInstanceId), s.Key.ProvidedService.Title, s.Select(m => _protocol.MessageFactory.CreateDiscoveredServiceMethod( m.Method.Name, m.Title, m.Method.InputMessage.Id, m.Method.OutputMessage.Id, Convert(m.Method.Type), m.Options.Select(o => _protocol.MessageFactory.CreateOption(o.Id, o.Value)).ToList())) .ToList()); using (var response = _protocol.MessageFactory.CreateServiceDiscoveryResponse(discoveredServices.ToList())) { Log.Info("Completed service discovery request {{{0}}} from {{{1}}}: {2}", request, sourceConnection, response); var serializedResponse = _protocol.Serializer.Serialize(response); try { await sourceChannel.Out .WriteAsync(new TransportMessageFrame(serializedResponse)) .ConfigureAwait(false); } catch { serializedResponse.Dispose(); throw; } } }