Пример #1
0
        private async Task <ExecutionResult> SubmitOrExecuteJobAsync(
            IChannel?channel,
            AzureSubmissionContext submissionContext,
            bool execute,
            CancellationToken cancellationToken)
        {
            if (ActiveWorkspace == null)
            {
                channel?.Stderr($"Please call {GetCommandDisplayName("connect")} before submitting a job.");
                return(AzureClientError.NotConnected.ToExecutionResult());
            }

            if (ActiveTarget?.TargetId == null)
            {
                channel?.Stderr($"Please call {GetCommandDisplayName("target")} before submitting a job.");
                return(AzureClientError.NoTarget.ToExecutionResult());
            }

            if (string.IsNullOrEmpty(submissionContext.OperationName))
            {
                channel?.Stderr($"Please pass a valid Q# operation name to {GetCommandDisplayName(execute ? "execute" : "submit")}.");
                return(AzureClientError.NoOperationName.ToExecutionResult());
            }

            var connectionResult = await RefreshConnectionAsync(channel);

            if (connectionResult.Status != ExecuteStatus.Ok)
            {
                return(connectionResult);
            }

            var machine = AzureFactory.CreateMachine(this.ActiveWorkspace, this.ActiveTarget.TargetId, this.StorageConnectionString);

            if (machine == null)
            {
                // We should never get here, since ActiveTarget should have already been validated at the time it was set.
                channel?.Stderr($"Unexpected error while preparing job for execution on target {ActiveTarget.TargetId}.");
                return(AzureClientError.InvalidTarget.ToExecutionResult());
            }

            channel?.Stdout($"Submitting {submissionContext.OperationName} to target {ActiveTarget.TargetId}...");

            IEntryPoint?entryPoint;

            try
            {
                entryPoint = EntryPointGenerator.Generate(submissionContext.OperationName, ActiveTarget.TargetId, ActiveTarget.RuntimeCapability);
            }
            catch (TaskCanceledException tce)
            {
                throw tce;
            }
            catch (UnsupportedOperationException)
            {
                channel?.Stderr($"{submissionContext.OperationName} is not a recognized Q# operation name.");
                return(AzureClientError.UnrecognizedOperationName.ToExecutionResult());
            }
            catch (CompilationErrorsException e)
            {
                e.Log(channel, Logger, $"The Q# operation {submissionContext.OperationName} could not be compiled as an entry point for job execution.");
                foreach (var message in e.Errors)
                {
                    channel?.Stderr(message);
                }
                return(AzureClientError.InvalidEntryPoint.ToExecutionResult());
            }

            try
            {
                var job = await entryPoint.SubmitAsync(machine, submissionContext);

                channel?.Stdout($"Job successfully submitted for {submissionContext.Shots} shots.");
                channel?.Stdout($"   Job name: {submissionContext.FriendlyName}");
                channel?.Stdout($"   Job ID: {job.Id}");
                MostRecentJobId = job.Id;
            }
            catch (TaskCanceledException tce)
            {
                throw tce;
            }
            catch (ArgumentException e)
            {
                var msg = $"Failed to parse all expected parameters for Q# operation {submissionContext.OperationName}.";
                Logger.LogError(e, msg);

                channel?.Stderr(msg);
                channel?.Stderr(e.Message);
                return(AzureClientError.JobSubmissionFailed.ToExecutionResult());
            }
            catch (Exception e)
            {
                channel?.Stderr($"Failed to submit Q# operation {submissionContext.OperationName} for execution.");
                channel?.Stderr(e.InnerException?.Message ?? e.Message);
                return(AzureClientError.JobSubmissionFailed.ToExecutionResult());
            }

            // If the command was not %azure.execute, simply return the job status.
            if (!execute)
            {
                return(await GetJobStatusAsync(channel, MostRecentJobId));
            }

            // If the command was %azure.execute, wait for the job to complete and return the job output.
            channel?.Stdout($"Waiting up to {submissionContext.ExecutionTimeout} seconds for Azure Quantum job to complete...");

            using var executionTimeoutTokenSource      = new CancellationTokenSource(TimeSpan.FromSeconds(submissionContext.ExecutionTimeout));
            using var executionCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(executionTimeoutTokenSource.Token, cancellationToken);
            {
                try
                {
                    CloudJob?cloudJob = null;
                    while (cloudJob == null || cloudJob.InProgress)
                    {
                        executionCancellationTokenSource.Token.ThrowIfCancellationRequested();
                        await Task.Delay(TimeSpan.FromSeconds(submissionContext.ExecutionPollingInterval), executionCancellationTokenSource.Token);

                        cloudJob = await ActiveWorkspace.GetJobAsync(MostRecentJobId, executionTimeoutTokenSource.Token);

                        channel?.Stdout($"[{DateTime.Now.ToLongTimeString()}] Current job status: {cloudJob?.Status ?? "Unknown"}");
                    }
                }
                catch (Exception e) when(e is TaskCanceledException || e is OperationCanceledException)
                {
                    Logger?.LogInformation($"Operation canceled while waiting for job execution to complete: {e.Message}");
                }
                catch (Exception e)
                {
                    channel?.Stderr($"Unexpected error while waiting for the results of the Q# operation.");
                    channel?.Stderr(e.InnerException?.Message ?? e.Message);
                    return(AzureClientError.JobSubmissionFailed.ToExecutionResult());
                }
            }

            return(await GetJobResultAsync(channel, MostRecentJobId, cancellationToken));
        }
Пример #2
0
        private async Task <ExecutionResult> ConnectToWorkspaceAsync(IChannel?channel,
                                                                     string subscriptionId,
                                                                     string resourceGroupName,
                                                                     string workspaceName,
                                                                     string location,
                                                                     TokenCredential credential,
                                                                     CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(location))
            {
                channel?.Stderr($"No location provided.");
                return(AzureClientError.NoWorkspaceLocation.ToExecutionResult());
            }

            location = GetNormalizedLocation(location, channel);
            if (string.IsNullOrWhiteSpace(location))
            {
                return(AzureClientError.InvalidWorkspaceLocation.ToExecutionResult());
            }

            try
            {
                var options = new QuantumJobClientOptions();

                // This value will be added as a prefix in the UserAgent when
                // calling the Azure Quantum APIs
                options.Diagnostics.ApplicationId = IsPythonUserAgent ? "IQ#/Py" : "IQ#";

                var workspace = AzureFactory.CreateWorkspace(
                    subscriptionId: subscriptionId,
                    resourceGroup: resourceGroupName,
                    workspaceName: workspaceName,
                    location: location,
                    credential: credential,
                    options: options);

                var providers = new List <ProviderStatusInfo>();
                var status    = workspace.ListProvidersStatusAsync(cancellationToken);
                await foreach (var s in status)
                {
                    providers.Add(s);
                }

                ActiveWorkspace    = workspace;
                AvailableProviders = providers;

                return(ExecuteStatus.Ok.ToExecutionResult());
            }
            catch (TaskCanceledException tce)
            {
                throw tce;
            }
            catch (Exception e)
            {
                var msg = $"The Azure Quantum workspace {workspaceName} in location {location} could not be reached.";
                Logger.LogError(e, msg);
                channel?.Stderr($"{msg} Please check the provided parameters and try again.");
                channel?.Stderr($"Error details:\n\n{e.Message}");

                return(AzureClientError.WorkspaceNotFound.ToExecutionResult());
            }
        }