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)); }
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()); } }