author | description | ms.date | ms.author | ms.service | ms.subservice | ms.topic | no-loc | title | uid | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
SoniaLopezBravo |
Learn how to manually manage your jobs using sessions, what are the job failure policies, and how to avoid session timeouts. |
10/24/2024 |
sonialopez |
azure-quantum |
qdk |
how-to |
|
Manage your Sessions |
microsoft.quantum.hybrid.interactive.how-to-sessions |
In Azure Quantum you can group multiple jobs against a single target, which allows you to manage jobs effectively. This is called a session. For more information, see Get started with sessions.
In this article, you learn how to manually manage your jobs using sessions, what are the job failure policies, and how to avoid session timeouts.
-
An Azure account with an active subscription. If you don’t have an Azure account, register for free and sign up for a pay-as-you-go subscription.
-
An Azure Quantum workspace. For more information, see Create an Azure Quantum workspace.
-
A Python environment with Python and Pip installed.
-
The Azure Quantum
azure-quantum
package. If you want to use Qiskit or Cirq, you need to install theazure-quantum
package with the [qiskit] or [cirq] tags.pip install --upgrade azure-quantum[qiskit]
Note
Sessions are managed with Python, even when running Q# inline code.
You can use the Job management blade in your Quantum workspace to view all top-level submitted items, including sessions and individual jobs that aren't associated with any session.
- Select the Job management blade in your Quantum workspace.
- Identify the jobs of type Session. In this view you can see the Unique ID of a Session in column Id and monitor its Status. The states of a session are:
- Waiting: Jobs within the session are being executed.
- Succeeded: Session has ended successfully.
- TimeOut: If no new job is submitted within the session for 10 minutes, that session times out. For more information, see Session timeouts.
- Failed: If a job within a session fails, that session ends and reports a status of Failed. For more information, see Job failure policy within sessions.
- Click on a session's name for more details.
- You can see the list of All jobs within the session and monitor their status.
The following table shows the Python commands to get the list of all sessions and all jobs for a given session.
Command | Description |
---|---|
workspace.list_sessions() or session.list_sessions() |
Retrieve a list of all sessions in a Quantum Workspace. |
workspace.get_session(sessionId) or session.get_session(sessionId) |
Retrieve the session with ID sessionId . Each session has a unique ID. |
workspace.list_session_jobs(sessionId) or session.list_session_jobs(sessionId) |
Retrieve a list of all jobs in the session with ID sessionId . Each session has a unique ID. |
For example, the following code defines a function that gets a session with a minimum number of jobs. Then, for that session, it lists all the jobs, the total number of jobs, and the first 10 jobs.
def get_a_session_with_jobs(min_jobs):
all_sessions = workspace.list_sessions() # list of all sessions
for session in all_sessions:
if len(workspace.list_session_jobs(session.id)) >= min_jobs:
return session
session = get_a_session_with_jobs(min_jobs=3) # Get a Session with at least 3 jobs
session_jobs = workspace.list_session_jobs(session.id) # List of all jobs within Session ID
print(f"Job count: {len(session_jobs)} \n")
print(f"First 10 jobs for session {session.id}:")
for job in session_jobs[0:10]:
print(f"Id: {job.id}, Name={job.details.name}")
We recommend following the steps in Get started with sessions to create a new session. You can also manually create sessions.
-
First, create a Session object.
from azure.quantum.job.session import Session, SessionDetails, SessionJobFailurePolicy import uuid session = Session( workspace=workspace, # required id=f"{uuid.uuid1()}", # optional, if not passed will use uuid.uuid1() name="", # optional, will be blank if not passed provider_id="ionq", # optional, if not passed will try to parse from the target target="ionq.simulator", # required job_failure_policy=SessionJobFailurePolicy.ABORT # optional, defaults to abort ) print(f"Session status: {session.details.status}")
[!NOTE] At this point, the session only exists on the client, and you can see that the status is None. To view the status of the session, you also need to create the session in the service.
-
To create a session in the service, you can use
workspace.open_session(session)
orsession.open()
. -
You can refresh the status and the session details with
session.refresh()
, or by getting a new session object from a session ID.same_session = workspace.get_session(session.id) print(f"Session: {session.details} \n") print(f"Session: {same_session.details} \n")
-
You can close a session with
session.close()
orworkspace.close_session(session)
. -
To attach the session to a target, you can use
target.latest_session
. -
You can wait for a session to be completed:
session_jobs = session.list_jobs() [session_job.id for session_job in session_jobs] import time while (session.details.status != "Succeeded" and session.details.status != "Failed" and session.details.status != "TimedOut"): session.refresh() time.sleep(5)
-
First, import the credentials of your Azure Quantum workspace.
import os resource_id = os.environ.get("AZURE_QUANTUM_RESOURCE_ID") location = os.environ.get("AZURE_QUANTUM_LOCATION")
-
Next, you create a Provider object.
from azure.quantum import Workspace from azure.quantum.qiskit import AzureQuantumProvider workspace = Workspace ( resource_id = resource_id, location = location ) provider = AzureQuantumProvider(workspace)
-
You create a quantum backend using the target you want to use. For example, the following code creates a quantum backend for IonQ simulator. For more information, see Create an Azure Quantum backend.
ionq_simulator_backend = provider.get_backend("ionq.simulator") provider_backend = ionq_simulator_backend backend_id = provider_backend.name()
-
To create a session object, you can use the
.open_session
function.from azure.quantum.job.session import Session, SessionJobFailurePolicy session = provider_backend.open_session(name="Azure Quantum Session", job_failure_policy=SessionJobFailurePolicy.CONTINUE) # optional, defaults to abort session.open() print("Creating session")
-
To attach the session manually created to the quantum backend, you can use
session = provider_backend.latest_session
. -
You can retrieve the jobs of your session using
session.list(jobs)
. -
You can close a session with
session.close()
. -
You can wait for a session to be completed:
print("Waiting for jobs to complete") import time while (session.details.status != "Succeeded" and session.details.status != "Failed" and session.details.status != "TimedOut"): session.refresh() time.sleep(5) print("Session status: " + session.details.status)
If your Q# operation takes input arguments, those arguments are passed during job submission, which is Python code. This means that you need to be careful to format your arguments as Q# objects.
When passing arguments as parameters to the job, they are formatted as Q# code when calling qsharp.compile
, so the values from Python need to be formatted into a string as valid Q# syntax.
Consider the following Q# program, which takes an integer, n
, and an array of angles, angle
, as input.
import Std.Measurement.*;
import Std.Arrays.*;
operation GenerateRandomBits(n: Int, angle: Double[]) : Result[] {
use qubits = Qubit[n]; // n parameter as the size of the qubit array
for q in qubits {
H(q);
}
R(PauliZ, angle[0], qubits[0]); // arrays as entry-points parameters
R(PauliZ, angle[1], qubits[1]);
let results = MeasureEachZ(qubits);
ResetAll(qubits);
return results;
}
You want to run GenerateRandomBits
operation three times with n=2
and different angles. You can use the following Python code to submit three jobs with different angles.
angle = [0.0, 0.0]
with target.open_session(name="Q# session of three jobs") as session:
target.submit(input_data=qsharp.compile(f"GenerateRandomBits(2, {angle})"), name="Job 1", shots=100) # First job submission
angle[0] += 1
target.submit(input_data=qsharp.compile(f"GenerateRandomBits(2, {angle})"), name="Job 2", shots=100) # Second job submission
angle[1] += 1
target.submit(input_data=qsharp.compile(f"GenerateRandomBits(2, {angle})"), name="Job 3", shots=100) # Third job submission
session_jobs = session.list_jobs()
[session_job.details.name for session_job in session_jobs]
In this example, because arrays in Python are already printed as [item0, item1, ...], the input arguments match the Q# formatting. For other Python data structures you might need more handling to get the string values inserted into the Q# in a compatible way. For example, a Q# tuple has to be in parentheses with comma separated values.
A session times out if no new job is submitted within the session for 10 minutes. The session reports a status of TimedOut. To avoid this situation, add a with
block using backend.open_session(name="Name")
, so the session close()
is invoked by the service at the end of the code block.
Note
If there are errors or bugs in your program, it might take more than 10 minutes to submit a new job after the previous jobs in the session have all completed.
The following code snippets show an example of a session times out after 10 minutes because no new jobs are submitted. To avoid that, the next code snippet shows how to use a with
block to create a session.
#Example of a session that times out
session = backend.open_session(name="Qiskit circuit session") # Session times out because only contains one job
backend.run(circuit=circuit, shots=100, job_name="Job 1")
#Example of a session that includes a with block to avoid timeout
with backend.open_session(name="Qiskit circuit session") as session: # Use a with block to submit multiple jobs within a session
job1 = backend.run(circuit=circuit, shots=100, job_name="Job 1") # First job submission
job1.wait_for_final_state()
job2 = backend.run(circuit=circuit, shots=100, job_name="Job 2") # Second job submission
job2.wait_for_final_state()
job3 = backend.run(circuit=circuit, shots=100, job_name="Job 3") # Third job submission
job3.wait_for_final_state()
The default policy for a session when a job fails is to end that session. If you submit an additional job within the same session, the service rejects it and the session reports a status of Failed. Any in progress jobs are canceled.
However, this behavior can be changed by specifying a job failure policy of job_failure_policy=SessionJobFailurePolicy.CONTINUE
, instead of the default SessionJobFailurePolicy.ABORT
, when creating the session. When the job failure policy is CONTINUE
, the service continues to accept jobs. The session reports a status of Failure(s) in this case, which will change to Failed once the session is closed.
If the session is never closed and times out, the status is TimedOut even if jobs have failed.
For example, the following program creates a session with three jobs. The first job fails because it specifies "garbage"
as input data. To avoid the end of the session at this point, the program shows how to add job_failure_policy=SessionJobFailurePolicy.CONTINUE
when creating the session.
#Example of a session that does not close but reports Failure(s) when a jobs fails
with target.open_session(name="JobFailurePolicy Continue", job_failure_policy=SessionJobFailurePolicy.CONTINUE) as session:
target.submit(input_data="garbage", name="Job 1") #Input data is missing, this job fails
target.submit(input_data=quil_program, name="Job 2") #Subsequent jobs are accepted because of CONTINUE policy
target.submit(input_data=quil_program, name="Job 3")
- Running hybrid quantum computing
- Get started with sessions