Swedish Healthcare Service - Health Condition Description
0.1.0 - CI Build
Sweden
Swedish Healthcare Service - Health Condition Description - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions
This page documents how aggregating services combine responses from multiple source systems.
When a consumer queries a national or regional aggregator, the aggregator:
sequenceDiagram
participant C as Consumer
participant A as Aggregator
participant S1 as Source 1
participant S2 as Source 2
participant S3 as Source 3
C->>A: Request (patientId)
par Parallel Queries
A->>S1: Request
A->>S2: Request
A->>S3: Request
end
par Responses
S1-->>A: Response 1 (10 items)
S2-->>A: Response 2 (5 items)
S3-->>A: Timeout/Error
end
A->>A: Merge responses
A->>A: Remove duplicates
A->>A: Sort by timestamp
A->>A: Apply limits
A-->>C: Aggregated Response<br/>(15 items + partial failure info)
Records are considered duplicates if they have the same record.id (document identifier):
Example:
<!-- Record from Source System 1 -->
<record>
<id root="550e8400-e29b-41d4-a716-446655440001"/>
<timestamp>20241015100000</timestamp>
</record>
<!-- Same record from Source System 2 (duplicate) -->
<record>
<id root="550e8400-e29b-41d4-a716-446655440001"/>
<timestamp>20241015100500</timestamp>
</record>
Detection Logic:
Map<String, Record> uniqueRecords = new HashMap<>();
for (Record record : allRecords) {
String recordId = record.getId().getRoot();
if (!uniqueRecords.containsKey(recordId)) {
uniqueRecords.put(recordId, record);
} else {
// Duplicate detected - keep most recent version
Record existing = uniqueRecords.get(recordId);
if (record.getTimestamp().isAfter(existing.getTimestamp())) {
uniqueRecords.put(recordId, record);
}
}
}
When duplicates are found, the aggregator selects the most recent version:
Selection Criteria:
Example:
Source 1: record.id = abc123, timestamp = 20241015100000
Source 2: record.id = abc123, timestamp = 20241015103000
Result: Keep Source 2 version (later timestamp)
Records are deduplicated within the same service domain only:
Aggregated results are sorted by timestamp in descending order (newest first):
Collections.sort(records, (r1, r2) ->
r2.getRecordTimestamp().compareTo(r1.getRecordTimestamp())
);
Primary Sort: record.timestamp (descending)
Record A: 20241127103000
Record B: 20241127094500
Record C: 20241115080000
Result order: A, B, C
Secondary Sort (if timestamps equal): documentId (lexicographic)
Record A: timestamp=20241127100000, id=doc-001
Record B: timestamp=20241127100000, id=doc-002
Result order: A, B (by id)
Some services may have additional sorting requirements:
GetAlertInformation:
GetDiagnosis:
Default Limit: 500 records per response
Rationale:
When results exceed the limit, pagination is used:
<GetCareDocumentationResponse>
<result>
<resultCode>INFO</resultCode>
<message>Showing first 500 of 1200 results</message>
</result>
<careDocumentation><!-- 500 records --></careDocumentation>
<hasMore>true</hasMore>
<hasMoreReference>ref-abc123-page2</hasMoreReference>
</GetCareDocumentationResponse>
Consumer Follow-up Request:
<GetCareDocumentation>
<patientId>...</patientId>
<hasMoreReference>ref-abc123-page2</hasMoreReference>
</GetCareDocumentation>
Before Aggregation: Each source system may apply its own limits
After Aggregation: Aggregator combines and applies overall limit
Timeout:
Source System 1: OK (150 records)
Source System 2: OK (80 records)
Source System 3: Timeout after 30 seconds
Error Response:
Source System 1: OK (150 records)
Source System 2: ERROR (ACCESS_DENIED)
Source System 3: OK (200 records)
System Unavailable:
Source System 1: OK (150 records)
Source System 2: Connection refused
Source System 3: OK (200 records)
Continue with Partial Results:
Response Structure:
<GetCareDocumentationResponse>
<result>
<resultCode>INFO</resultCode>
<message>Partial results: 2 of 3 systems responded successfully</message>
</result>
<careDocumentation><!-- Records from successful systems --></careDocumentation>
<failedSources>
<failedSource>
<sourceSystemHSAId>SE2321000016-9999</sourceSystemHSAId>
<errorCode>TIMEOUT</errorCode>
<errorMessage>No response within 30 seconds</errorMessage>
</failedSource>
</failedSources>
</GetCareDocumentationResponse>
Display Partial Results:
Consumer should:
1. Display available data
2. Inform user of incomplete results
3. Show which sources failed
4. Offer retry option
User Message Example:
"Showing care documentation from 2 of 3 available sources.
Unable to retrieve data from: Hospital XYZ (timeout)
[Retry]"
Per-Source Timeout: 27 seconds maximum
Total Request Timeout: 30 seconds maximum
Configuration Example:
ExecutorService executor = Executors.newFixedThreadPool(10);
List<Future<Response>> futures = new ArrayList<>();
// Submit parallel requests
for (SourceSystem source : sources) {
Future<Response> future = executor.submit(() ->
querySource(source, request)
);
futures.add(future);
}
// Collect with timeout
List<Response> responses = new ArrayList<>();
for (Future<Response> future : futures) {
try {
Response response = future.get(27, TimeUnit.SECONDS);
responses.add(response);
} catch (TimeoutException e) {
// Log timeout, continue with other responses
recordTimeout(source);
}
}
Engagement Index Lag:
Mitigation:
Timestamp Comparison:
Example:
Care Document from 2024-11-27 10:30 (today)
Care Document from 2024-11-15 08:00 (12 days ago)
Care Document from 2023-05-20 14:00 (1 year ago)
Logical Errors (e.g., ACCESS_DENIED):
<result>
<resultCode>INFO</resultCode>
<message>Unable to retrieve data from 1 source due to access restrictions</message>
</result>
<failedSources>
<failedSource>
<sourceSystemHSAId>SE2321000016-8888</sourceSystemHSAId>
<errorCode>ACCESS_DENIED</errorCode>
<errorMessage>Patient has blocked access to this care giver</errorMessage>
</failedSource>
</failedSources>
Technical Errors:
<failedSources>
<failedSource>
<sourceSystemHSAId>SE2321000016-7777</sourceSystemHSAId>
<errorCode>TECHNICAL_ERROR</errorCode>
<errorMessage>Database connection failed</errorMessage>
</failedSource>
</failedSources>
Complete Failure (no successful responses):
<result>
<resultCode>TECHNICAL_ERROR</resultCode>
<message>Unable to retrieve data from any source system</message>
</result>
EI Failure:
<result>
<resultCode>TECHNICAL_ERROR</resultCode>
<message>Engagement Index unavailable</message>
</result>
Not Recommended for Patient Data:
Acceptable for Metadata:
Thread Pool Configuration:
// Configure thread pool for parallel queries
int poolSize = Math.min(sourceCount, 20); // Max 20 parallel
ExecutorService executor = Executors.newFixedThreadPool(poolSize);
// Connection pool per source
HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.executor(executor)
.build();
Protect Against Failing Sources:
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("sourceSystem");
Supplier<Response> decoratedSupplier =
CircuitBreaker.decorateSupplier(circuitBreaker,
() -> querySource(source, request));
Try<Response> result = Try.of(decoratedSupplier);
States:
| Metric | Description | Target |
|---|---|---|
| Response Time | Total aggregation time | p95 < 10 sec |
| Source Response Time | Per-source query time | p95 < 5 sec |
| Deduplication Rate | % of duplicate records | Monitor trend |
| Partial Failure Rate | % of requests with failures | < 5% |
| Timeout Rate | % of source timeouts | < 2% |
Warning Alerts:
Critical Alerts: