Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix timeout issues when querying instances of a local study in Orthanc #532

Merged
merged 3 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions pixl_imaging/src/pixl_imaging/_orthanc.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,16 @@ async def get_local_study(self, study_id: str) -> Any:
"""Query local Orthanc instance for study."""
return await self._get(f"/studies/{study_id}")

async def get_local_study_statistics(self, study_id: str) -> Any:
"""Query local Orthanc instance for study statistics."""
return await self._get(f"/studies/{study_id}/statistics")

async def get_local_study_instances(self, study_id: str) -> Any:
"""Get the instances of a study."""
return await self._get(f"/studies/{study_id}/instances")
return await self._get(
f"/studies/{study_id}/instances?short=true",
timeout=self.dicom_timeout, # this API call can sometimes take several minutes
)

async def query_remote(self, data: dict, modality: str) -> Optional[str]:
"""Query a particular modality, available from this node"""
Expand Down Expand Up @@ -154,13 +161,15 @@ async def job_state(self, job_id: str) -> Any:
# See: https://book.orthanc-server.com/users/advanced-rest.html#jobs-monitoring
return await self._get(f"/jobs/{job_id}")

async def _get(self, path: str) -> Any:
async def _get(self, path: str, timeout: int | None = None) -> Any:
# Optionally override default http timeout
http_timeout = timeout or self.http_timeout
async with (
aiohttp.ClientSession() as session,
session.get(
f"{self._url}{path}",
auth=self._auth,
timeout=self.http_timeout,
timeout=http_timeout,
) as response,
):
return await _deserialise(response)
Expand Down
26 changes: 16 additions & 10 deletions pixl_imaging/src/pixl_imaging/_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,15 +283,9 @@ async def _get_missing_instances(

Return a list of missing instance UIDs (empty if none missing)
"""
# First get all SOPInstanceUIDs for the study that are in Orthanc Raw
orthanc_raw_sop_instance_uids = []
for resource in resources:
study_instances = await orthanc_raw.get_local_study_instances(study_id=resource)
orthanc_raw_sop_instance_uids.extend(
[instance["MainDicomTags"]["SOPInstanceUID"] for instance in study_instances]
)
missing_instances: list[dict[str, str]] = []

# Now query the VNA / PACS for the study instances
# First query the VNA / PACS for the study instances
study_query_answers = await orthanc_raw.get_remote_query_answers(study_query_id)
instances_queries_and_answers = []
for answer_id in study_query_answers:
Expand All @@ -302,13 +296,25 @@ async def _get_missing_instances(
instances_queries_and_answers.extend(
[(instances_query_id, answer) for answer in instances_query_answers]
)
num_remote_instances = len(instances_queries_and_answers)

missing_instances: list[dict[str, str]] = []
num_local_instances = 0
for resource in resources:
study_statistics = await orthanc_raw.get_local_study_statistics(study_id=resource)
num_local_instances += int(study_statistics["CountInstances"])

if len(instances_queries_and_answers) == len(orthanc_raw_sop_instance_uids):
if num_remote_instances == num_local_instances:
logger.debug("No missing instances for study {}", study.message.study_uid)
return missing_instances

# Get all SOPInstanceUIDs for the study that are in Orthanc Raw
orthanc_raw_sop_instance_uids = []
for resource in resources:
study_instances = await orthanc_raw.get_local_study_instances(study_id=resource)
orthanc_raw_sop_instance_uids.extend(
[instance["MainDicomTags"]["0008,0018"] for instance in study_instances]
)

# If the SOPInstanceUID is not in the list of instances in Orthanc Raw
# retrieve the instance from the VNA / PACS
query_tags = ["0020,000d", "0020,000e", "0008,0018"]
Expand Down