The IBM FHIR Server supports hard delete using the custom FHIR Operation Framework. The operation is called $erase; you can always read the design document.
Version Specific Hard Delete – the latest version may not be hard deleted, you must execute a soft DELETE, then a hard delete. Otherwise, all versions may be deleted.
By default, the $erase operation is not enabled, and must be set to true, and the roles allowed to execute the operation, can be tweaked to FHIROperationAdmin or FHIRUsers.
Property
Type
Description
fhirServer/operations/erase/enabled
boolean
Enables the $erase operation
fhirServer/operations/erase/allowedRoles
list
The list of allowed roles, allowed entries are: FHIRUsers every authenticated user, FHIROperationAdmin which is authenticated FHIRAdmin users
Properties
The fhir-server-config.json should be amended with a snippet like the following:
As the $erase operation uses stored procedures for Db2 and functions for Postgres, the data schema must be updated to the 4.8.3 level. It’s also worth noting that Derby is also supported as it uses the same DAO as the Db2 and Postgres to run.
A tip, you should search for the references to the Patient’s ResourceId, and delete the referenced resources in a Transaction Bundle. Net – Search, Assemble Bundle, Execute Batch.
docker logs cde61943964464b528eb77d132fd2a4952e0eaf43588da1c9b6bb2fa584f0608
...
[6/16/21, 15:31:34:533 UTC] 0000002a FeatureManage A CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 17.665 seconds.
The IBM FHIR Server supports storage providers S3 (aws-s3,ibm-cos), File System (file), and now Azure (azure-blob).
I recently implemented support for the Azure Blob Service in IBM/FHIR Pull Request #2413. The code that supports the Azure client uses the OK Http library and not Netty to communicate with the backend. The storage provider is implemented as AzureProvider, and uses the Java – AppendBlobClient to facilitate export. To facilitate import, the code uses the BlobClient to read from a location in 10Kb blocks, and reassemble when a full block is reached. Importantly, this is done in a way to ensure full resources are returned up to a 2Gb limit.
Overview Video
If you want to use the IBM FHIR Server’s bulk data feature with the IBM FHIR Server, use the following recipe:
5. Enter the appropriate subscription and resource group
6. Give it a name such as fhirintegrationit
7. Click Review+Create
8. Click Create
You’ll see Deployment in Progress for a period of time.
Once it is done, you see Your deployment is complete, proceed to the next steps.
9. Click Go to Resource
10. Click on Access Key
11. Click Show keys and copy the key1’s Connection string. It’ll look like DefaultEndpointsProtocol=https;AccountName=fhirintegrationit;AccountKey=HIDDEN==;EndpointSuffix=core.windows.net
12. Click on Data > Containers
13. Click +Container
14. Fill in the container details and call it bulkdata
You are now ready to use this with the IBM FHIR Server from the main branch. If you need to clone the repo go to IBM/FHIR.
16. Build the Maven Projects and the Docker Build. You should see “[INFO] BUILD SUCCESS” after each Maven build, and “=> naming to docker.io/ibmcom/ibm-fhir-server:latest” when the Docker build is successful.
18. Open the fhir-server-config.json and update fhirServer/bulkdata/storageProviders/default entry to be the connection is updated to your Connection string from above.
17. Start the Docker container, and capture the container id. It’s going to take a few moments to start up as it lays down the test database.
docker logs cde61943964464b528eb77d132fd2a4952e0eaf43588da1c9b6bb2fa584f0608
...
[6/16/21, 15:31:34:533 UTC] 0000002a FeatureManage A CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 17.665 seconds.
19. Create an $import request and capture the content-location header.
20. Check and poll until you get response code 200 (you should only get 202 in the interim) until you see (note 99 failed validation which is expected):
I’ve been debugging a drop tablespace issue on Db2 – IBM/FHIR: 2354. The core issue was a timing problem with lots of partitions dettaching. This adds a delay to the dropTablespace so the async operation can complete, and cleanly exit with a specific error code so downstream consumers can work around the issue.
When debugging why a partition hasn’t dettached, I found that it’s worth checking the details when a drop tablespace fails:
[db2inst1@53fe3a4d3ad2 ~]$ db2 list utilities show detail
ID = 18435
Type = ASYNCHRONOUS PARTITION DETACH
Database Name = FHIRDB
Member Number = 0
Description = Finalize the detach for partition '3' of table 'FHIRDATA.PARAMETER_NAMES'
Start Time = 06/08/2021 16:31:05.526513
State = Executing
Invocation Type = Automatic
Progress Monitoring:
Description = Performing detach operation and
making the target table available; new compilations blocked
Start Time = 06/08/2021 16:31:10.836936
I’ve attached a useful partition.sql to demo partitions and check the system catalog.
Shows the contents of the functions in the schema.
SELECT pg_get_functiondef(f.oid)
FROM pg_catalog.pg_proc f
INNER JOIN pg_catalog.pg_namespace n ON (f.pronamespace = n.oid)
WHERE n.nspname = 'fhirdata';
Show all the details of the functions in the schema.
SELECT *
FROM pg_catalog.pg_proc f
INNER JOIN pg_catalog.pg_namespace n ON (f.pronamespace = n.oid)
WHERE n.nspname = 'fhirdata';
Tracing Bulk Data with Cloud Object Storage
I wanted to figure out why my code was failing to connect to the backend S3 bucket.
I used the environment variable in my docker image called TRACE_SPEC. TRACE_SPEC is loaded into the logging as the traceSpecification.
I set this to *=info:com.ibm.cloud.*=FINEST which spits out great detail to S3 using the IBM COS SDK.
The output looks like:
With this level of trace, you can really dive into the connection, and determine what is going on.
Note, if you want the whole picture of what is happening with COS and JavaBatch and BulkData, use the following:
Note, the Minio container will create local certificates.
Using your MINIO_ROOT_PASSWORD echo ${MINIO_ROOT_PASSWORD}, log in to your Minio instance.
Create a Bucket (folder), look in the lower left. Name it fhirbulkdata.
Create Bucket
You should see the bucket.
Bucket
6. Download the [Sample NDJSON](https://github.com/IBM/FHIR/blob/main/fhir-server-test/src/test/resources/testdata/import-operation/test-import.ndjson)
Update the fhir-server-config.json fhirServer/bulkdata with the following snippet to use hmac and bulkdata. Be sure to update fhirServer/bulkdata/storageProviders/minio/accessKeyId to fhirAccessKey and fhirServer/bulkdata/storageProviders/minio/secretAccessKey to your MINIO_ROOT_PASSWORD.
You’ll see the container id output 60a5f1cae6d677d80772f1736db1be74836a8a4845fcccc81286b7c557bc2d86.
Check that the applications are started using the container id.
$ docker logs 60a | grep -i started
[4/21/21, 20:55:58:449 UTC] 00000001 FrameworkMana I CWWKE0002I: The kernel started after 1.43 seconds
[4/21/21, 20:55:58:464 UTC] 0000002a FeatureManage I CWWKF0007I: Feature update started.
[4/21/21, 20:56:01:328 UTC] 00000030 AppMessageHel A CWWKZ0001I: Application fhir-openapi started in 1.588 seconds.
[4/21/21, 20:56:03:141 UTC] 00000031 AppMessageHel A CWWKZ0001I: Application fhir-bulkdata-webapp started in 3.402 seconds.
[4/21/21, 20:56:07:824 UTC] 0000002d AppMessageHel A CWWKZ0001I: Application fhir-server-webapp started in 7.871 seconds.
[4/21/21, 20:56:07:868 UTC] 0000002a TCPPort I CWWKO0219I: TCP Channel defaultHttpEndpoint-ssl has been started and is now listening for requests on host * (IPv4) port 9443.
[4/21/21, 20:56:07:880 UTC] 0000002a FeatureManage A CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 10.885 seconds.
Scan the response.json for any status that is not "status": "201". For example, the status is in the family of User Request Error or Server Side Error.
curl -k -o data.ndjson 'https://localhost:9000/fhirbulkdata/hnFKv4BahpfK2iCnlPHOvnVknZVCVbgrBKwMn2HWCgg/Patient_1.ndjson?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=fhirAccessKey%2F20210423%2Fus%2Fs3%2Faws4_request&X-Amz-Date=20210423T002551Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=21e52030687241b9380b8985d6ee4793328955a22bda3adabe0e724175947d58'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4266 100 4266 0 0 20809 0 --:--:-- --:--:-- --:--:-- 20708
Look at the content and you’ll see it’s an ndjson.
data.ndjson
You now have a working environment start-to-end of the Bulk Data on IBM FHIR Server.
Addendum
File Provider
By changing X-FHIR-BULKDATA-PROVIDER to default, you can use the mapped volume /output/bulkdata to export and import from a local directory.
Logs
You can see the job logs using:
docker logs nervous_boyd
docker exec -it nervous_boyd cat /logs/joblogs/<path to job>
Networking issues
If you hit issues where the two images don’t talk to each other, please connect them to the same network:
You’ll see the container id output 60a5f1cae6d677d80772f1736db1be74836a8a4845fcccc81286b7c557bc2d86.
Check that the applications are started using the container id.
$ docker logs 60a | grep -i started
[4/21/21, 20:55:58:449 UTC] 00000001 FrameworkMana I CWWKE0002I: The kernel started after 1.43 seconds
[4/21/21, 20:55:58:464 UTC] 0000002a FeatureManage I CWWKF0007I: Feature update started.
[4/21/21, 20:56:01:328 UTC] 00000030 AppMessageHel A CWWKZ0001I: Application fhir-openapi started in 1.588 seconds.
[4/21/21, 20:56:03:141 UTC] 00000031 AppMessageHel A CWWKZ0001I: Application fhir-bulkdata-webapp started in 3.402 seconds.
[4/21/21, 20:56:07:824 UTC] 0000002d AppMessageHel A CWWKZ0001I: Application fhir-server-webapp started in 7.871 seconds.
[4/21/21, 20:56:07:868 UTC] 0000002a TCPPort I CWWKO0219I: TCP Channel defaultHttpEndpoint-ssl has been started and is now listening for requests on host * (IPv4) port 9443.
[4/21/21, 20:56:07:880 UTC] 0000002a FeatureManage A CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 10.885 seconds.
Scan the response.json for any status that is not "status": "201". For example, the status is in the family of User Request Error or Server Side Error.
Note: DUMMY_PASSWORD should be set to your environment.
Scan the response.json for any status that is not "status": "201". For example, the status is in the family of User Request Error or Server Side Error.
Check the response.json and find the id for Patient (it should be the first one).