private async Task <T> InvokeAsync <T>( string token, InvokeArgs args, InvokeOptions?options, bool convertResult) { var label = $"Invoking function: token={token} asynchronously"; Log.Debug(label); // Be resilient to misbehaving callers. args ??= InvokeArgs.Empty; // Wait for all values to be available, and then perform the RPC. var argsDict = await args.ToDictionaryAsync().ConfigureAwait(false); var serialized = await SerializeAllPropertiesAsync( $"invoke:{token}", argsDict, await this.MonitorSupportsResourceReferences().ConfigureAwait(false)).ConfigureAwait(false); Log.Debug($"Invoke RPC prepared: token={token}" + (_excessiveDebugOutput ? $", obj={serialized}" : "")); var provider = await ProviderResource.RegisterAsync(GetProvider(token, options)).ConfigureAwait(false); var result = await this.Monitor.InvokeAsync(new InvokeRequest { Tok = token, Provider = provider ?? "", Version = options?.Version ?? "", Args = serialized, }); if (result.Failures.Count > 0) { var reasons = ""; foreach (var reason in result.Failures) { if (reasons != "") { reasons += "; "; } reasons += $"{reason.Reason} ({reason.Property})"; } throw new InvokeException($"Invoke of '{token}' failed: {reasons}"); } if (!convertResult) { return(default !);
private async Task <PrepareResult> PrepareResourceAsync( string label, Resource res, bool custom, bool remote, ResourceArgs args, ResourceOptions options) { /* IMPORTANT! We should never await prior to this line, otherwise the Resource will be partly uninitialized. */ // Before we can proceed, all our dependencies must be finished. var type = res.GetResourceType(); var name = res.GetResourceName(); LogExcessive($"Gathering explicit dependencies: t={type}, name={name}, custom={custom}, remote={remote}"); var explicitDirectDependencies = new HashSet <Resource>( await GatherExplicitDependenciesAsync(options.DependsOn).ConfigureAwait(false)); LogExcessive($"Gathered explicit dependencies: t={type}, name={name}, custom={custom}, remote={remote}"); // Serialize out all our props to their final values. In doing so, we'll also collect all // the Resources pointed to by any Dependency objects we encounter, adding them to 'propertyDependencies'. LogExcessive($"Serializing properties: t={type}, name={name}, custom={custom}, remote={remote}"); var dictionary = await args.ToDictionaryAsync().ConfigureAwait(false); var(serializedProps, propertyToDirectDependencies) = await SerializeResourcePropertiesAsync( label, dictionary, await this.MonitorSupportsResourceReferences().ConfigureAwait(false)).ConfigureAwait(false); LogExcessive($"Serialized properties: t={type}, name={name}, custom={custom}, remote={remote}"); // Wait for the parent to complete. // If no parent was provided, parent to the root resource. LogExcessive($"Getting parent urn: t={type}, name={name}, custom={custom}, remote={remote}"); var parentUrn = options.Parent != null ? await options.Parent.Urn.GetValueAsync().ConfigureAwait(false) : await GetRootResourceAsync(type).ConfigureAwait(false); LogExcessive($"Got parent urn: t={type}, name={name}, custom={custom}, remote={remote}"); string?providerRef = null; if (custom) { var customOpts = options as CustomResourceOptions; providerRef = await ProviderResource.RegisterAsync(customOpts?.Provider).ConfigureAwait(false); } var providerRefs = new Dictionary <string, string>(); if (remote && options is ComponentResourceOptions componentOpts) { // If only the Provider opt is set, move it to the Providers list for further processing. if (componentOpts.Provider != null && componentOpts.Providers.Count == 0) { componentOpts.Providers.Add(componentOpts.Provider); componentOpts.Provider = null; } foreach (var provider in componentOpts.Providers) { var pref = await ProviderResource.RegisterAsync(provider).ConfigureAwait(false); if (pref != null) { providerRefs.Add(provider.Package, pref); } } } // Collect the URNs for explicit/implicit dependencies for the engine so that it can understand // the dependency graph and optimize operations accordingly. // The list of all dependencies (implicit or explicit). var allDirectDependencies = new HashSet <Resource>(explicitDirectDependencies); var allDirectDependencyUrns = await GetAllTransitivelyReferencedResourceUrnsAsync(explicitDirectDependencies).ConfigureAwait(false); var propertyToDirectDependencyUrns = new Dictionary <string, HashSet <string> >(); foreach (var(propertyName, directDependencies) in propertyToDirectDependencies) { allDirectDependencies.AddRange(directDependencies); var urns = await GetAllTransitivelyReferencedResourceUrnsAsync(directDependencies).ConfigureAwait(false); allDirectDependencyUrns.AddRange(urns); propertyToDirectDependencyUrns[propertyName] = urns; } // Wait for all aliases. Note that we use 'res._aliases' instead of 'options.aliases' as // the former has been processed in the Resource constructor prior to calling // 'registerResource' - both adding new inherited aliases and simplifying aliases down // to URNs. var aliases = new List <string>(); var uniqueAliases = new HashSet <string>(); foreach (var alias in res._aliases) { var aliasVal = await alias.ToOutput().GetValueAsync().ConfigureAwait(false); if (uniqueAliases.Add(aliasVal)) { aliases.Add(aliasVal); } } return(new PrepareResult( serializedProps, parentUrn ?? "", providerRef ?? "", providerRefs, allDirectDependencyUrns, propertyToDirectDependencyUrns, aliases)); void LogExcessive(string message) { if (_excessiveDebugOutput) { Log.Debug(message); } } }