Orchestration
Multi-study orchestration engine for iMednet SDK.
Provides MultiStudyOrchestrator for executing pipeline functions
concurrently across multiple iMednet study boundaries with fault isolation,
telemetry context propagation, and normalized result reporting.
Quick start
from imednet import ImednetSDK, MultiStudyOrchestrator
def my_pipeline(study_key, sdk, study_logger, **kwargs):
study_logger.info("Processing study")
subjects = sdk.subjects.list(study_key=study_key)
return {"subject_count": len(list(subjects))}
with ImednetSDK() as sdk:
orchestrator = MultiStudyOrchestrator(sdk, max_workers=4)
results = orchestrator.execute_pipeline(my_pipeline)
for study_key, result in results.items():
if result["status"] == "SUCCESS":
print(f"{study_key}: {result['data']}")
else:
print(f"{study_key}: FAILED — {result['error']}")
Public API
MultiStudyOrchestrator— main orchestration engineStudyContextLogAdapter— per-study log adaptermake_study_logger()— factory for study-bound loggersOrchestratorResult— per-study result schema (TypedDict)StudyWorkerCallable— protocol for pipeline callables
Errors
OrchestratorError— base orchestration errorFilterConflictError— raised when both whitelist and blacklist are provided simultaneously
- class imednet.orchestration.MultiStudyOrchestrator[source]
Bases:
objectOrchestrates pipeline execution across multiple active clinical trial boundaries.
The SDK instance passed at construction is treated as an immutable read-only resource — no worker thread may mutate its transport, authentication state, or connection pool during parallel execution.
- Parameters:
sdk (
Any) – A fully initializedImednetSDKinstance. The orchestrator stores a reference (not a copy) and treats it as immutable.max_workers (
int) – Maximum number of concurrent worker threads. Defaults to 4. Set to 1 to force sequential execution (useful for debugging).
Example:
with ImednetSDK(api_key=..., security_key=...) as sdk: orchestrator = MultiStudyOrchestrator(sdk, max_workers=8) results = orchestrator.execute_pipeline(my_pipeline_func)
- execute_pipeline(pipeline_func, whitelist=None, blacklist=None, *args, **kwargs)[source]
Execute a pipeline function concurrently across resolved study contexts.
- Return type:
dict[str,OrchestratorResult]- Parameters:
pipeline_func (StudyWorkerCallable[Any]) –
whitelist (set[str] | None) –
blacklist (set[str] | None) –
args (Any) –
kwargs (Any) –
- property max_workers: int
Maximum number of concurrent worker threads.
- resolve_active_studies(whitelist=None, blacklist=None)[source]
Query the iMednet registry and apply filtering rules.
Calls
self._sdk.studies.list()to fetch the live study inventory, then applies the whitelist OR blacklist (mutually exclusive).- Parameters:
whitelist (
Optional[set[str]]) – If provided, only studies whosestudyKeyis in this set are included. Mutually exclusive withblacklist.blacklist (
Optional[set[str]]) – If provided, studies whosestudyKeyis in this set are excluded. Mutually exclusive withwhitelist.
- Return type:
list[str]- Returns:
Ordered list of study key strings targeting this execution run.
- Raises:
FilterConflictError – When both
whitelistandblacklistare non-empty simultaneously.
- property sdk: Any
The shared read-only SDK instance.
- class imednet.orchestration.OrchestratorResult[source]
Bases:
TypedDictNormalized result entry returned per study by
execute_pipeline.-
data:
Optional[Any]
-
duration_seconds:
float
-
error:
Optional[str]
-
status:
str
-
data:
- class imednet.orchestration.StudyContextLogAdapter[source]
Bases:
LoggerAdapterA logger adapter that enriches records with a bound study key.
- __init__(logger, study_key)[source]
Initialize the adapter with a logger and a dict-like object which provides contextual information. This constructor signature allows easy stacking of LoggerAdapters, if so desired.
You can effectively pass keyword arguments as shown in the following example:
adapter = LoggerAdapter(someLogger, dict(p1=v1, p2=”v2”))
- Parameters:
logger (Logger) –
study_key (str) –
- Return type:
None
- process(msg, kwargs)[source]
Inject
study_keyandstudyKeyinto the log recordextramapping.- Return type:
tuple[Any,MutableMapping[str,Any]]- Parameters:
msg (Any) –
kwargs (MutableMapping[str, Any]) –
- property study_key: str
The study identifier bound to this adapter.
- class imednet.orchestration.StudyWorkerCallable[source]
Bases:
Protocol[T_Output]Defines the explicit signature required for injected pipeline tasks.
Pipeline callables injected into
MultiStudyOrchestrator.execute_pipelinemust conform to this protocol.- __init__(*args, **kwargs)
- imednet.orchestration.make_study_logger(study_key)[source]
Create a
StudyContextLogAdapterfor a study key.- Parameters:
study_key (
str) – The study identifier to bind to log records.- Return type:
- Returns:
A logger adapter that enriches records with the study key.
- class imednet.orchestration.MultiStudyOrchestrator[source]
Bases:
objectOrchestrates pipeline execution across multiple active clinical trial boundaries.
The SDK instance passed at construction is treated as an immutable read-only resource — no worker thread may mutate its transport, authentication state, or connection pool during parallel execution.
- Parameters:
sdk (
Any) – A fully initializedImednetSDKinstance. The orchestrator stores a reference (not a copy) and treats it as immutable.max_workers (
int) – Maximum number of concurrent worker threads. Defaults to 4. Set to 1 to force sequential execution (useful for debugging).
Example:
with ImednetSDK(api_key=..., security_key=...) as sdk: orchestrator = MultiStudyOrchestrator(sdk, max_workers=8) results = orchestrator.execute_pipeline(my_pipeline_func)
- execute_pipeline(pipeline_func, whitelist=None, blacklist=None, *args, **kwargs)[source]
Execute a pipeline function concurrently across resolved study contexts.
- Return type:
dict[str,OrchestratorResult]- Parameters:
pipeline_func (StudyWorkerCallable[Any]) –
whitelist (set[str] | None) –
blacklist (set[str] | None) –
args (Any) –
kwargs (Any) –
- property max_workers: int
Maximum number of concurrent worker threads.
- resolve_active_studies(whitelist=None, blacklist=None)[source]
Query the iMednet registry and apply filtering rules.
Calls
self._sdk.studies.list()to fetch the live study inventory, then applies the whitelist OR blacklist (mutually exclusive).- Parameters:
whitelist (
Optional[set[str]]) – If provided, only studies whosestudyKeyis in this set are included. Mutually exclusive withblacklist.blacklist (
Optional[set[str]]) – If provided, studies whosestudyKeyis in this set are excluded. Mutually exclusive withwhitelist.
- Return type:
list[str]- Returns:
Ordered list of study key strings targeting this execution run.
- Raises:
FilterConflictError – When both
whitelistandblacklistare non-empty simultaneously.
- property sdk: Any
The shared read-only SDK instance.
- class imednet.orchestration.StudyContextLogAdapter[source]
Bases:
LoggerAdapterA logger adapter that enriches records with a bound study key.
- __init__(logger, study_key)[source]
Initialize the adapter with a logger and a dict-like object which provides contextual information. This constructor signature allows easy stacking of LoggerAdapters, if so desired.
You can effectively pass keyword arguments as shown in the following example:
adapter = LoggerAdapter(someLogger, dict(p1=v1, p2=”v2”))
- Parameters:
logger (Logger) –
study_key (str) –
- Return type:
None
- process(msg, kwargs)[source]
Inject
study_keyandstudyKeyinto the log recordextramapping.- Return type:
tuple[Any,MutableMapping[str,Any]]- Parameters:
msg (Any) –
kwargs (MutableMapping[str, Any]) –
- property study_key: str
The study identifier bound to this adapter.
- imednet.orchestration.OrchestratorResult = <class 'imednet.orchestration.types.OrchestratorResult'>[source]
Normalized result entry returned per study by
execute_pipeline.
- imednet.orchestration.StudyWorkerCallable = <class 'imednet.orchestration.types.StudyWorkerCallable'>[source]
Defines the explicit signature required for injected pipeline tasks.
Pipeline callables injected into
MultiStudyOrchestrator.execute_pipelinemust conform to this protocol.
Orchestration Errors
- exception imednet.errors.OrchestratorError[source]
Bases:
ImednetErrorBase exception for all orchestration-layer failures.
Raised when the
MultiStudyOrchestratorencounters a structural or configuration error that prevents pipeline execution from starting.Individual per-study runtime failures are NOT raised as exceptions — they are captured in the
OrchestratorResultresult matrix withstatus="FAILED".
- exception imednet.errors.FilterConflictError[source]
Bases:
OrchestratorErrorRaised when both whitelist and blacklist are non-empty simultaneously.
The whitelist and blacklist filters are mutually exclusive operations. Providing both simultaneously creates ambiguous behavior and is rejected at validation time before any study resolution occurs.
Example:
# This raises FilterConflictError — a study key cannot be in both: orchestrator.execute_pipeline( my_func, whitelist={"STUDY-A", "STUDY-B"}, blacklist={"STUDY-C"}, )