Hawthorn contains everything required to set up a tiny, self-contained FHIR® terminology service. Currently, the following operations are supported:
To get started, sign up for a UMLS Metathesaurus License. This is required for access to the underlying UMLS terminology data, and typically takes 1-3 days to process.
After receiving access to UMLS Metathesaurus, your UMLS profile contains the API key needed for setting up the service.
Clone this repository, then build the service as a Docker container:
NOTE: This will download the entire ~4 GB UMLS metathesaurus release, and run a build script to extract the code system data from the compressed file.
docker build --build-arg UMLS_API_KEY=$UMLS_API_KEY -t hawthorn:latest .
docker run -it -p '29927:29927' hawthorn:latest
# Alternatively, build the service directly
# This produces two primary output files:
# - umls.db, a sqlite DB containing code system data
# - hawthorn, the statically compiled server binary
make build
Due to the "embedded" sqlite database, performance is excellent even at high load. To benchmark, CodeSystem/$lookup
repeated queries for a thousand random codes are sent as fast as possible over a single connection, to simulate usage of
the service as a sidecar. The benchmark was performed using K6, see the benchmark script
for more details.
tl;dr Served 6,500+ code lookups per second, with p99 latency <0.5 ms and p99.99 latency <5 ms
> k6 run --duration 7m --summary-trend-stats 'avg,min,med,p(75),p(90),p(95),p(99),p(99.9),p(99.99),max' k6.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: k6.js
scenarios: (100.00%) 1 scenario, 1 max VUs, 7m30s max duration (incl. graceful stop):
* default: 1 looping VUs for 7m0s (gracefulStop: 30s)
✓ status was 200
✓ body was right
checks.........................: 100.00% ✓ 5725472 ✗ 0
data_received..................: 2.9 GB 7.0 MB/s
data_sent......................: 425 MB 1.0 MB/s
http_req_blocked...............: avg=684ns min=299ns med=559ns p(75)=823ns p(90)=1.08µs p(95)=1.24µs
p(99)=1.63µs p(99.9)=6.57µs p(99.99)=18.77µs max=3.27ms
http_req_connecting............: avg=0ns min=0s med=0s p(75)=0s p(90)=0s p(95)=0s
p(99)=0s p(99.9)=0s p(99.99)=0s max=159.48µs
http_req_duration..............: avg=113.8µs min=59.21µs med=100.94µs p(75)=120.48µs p(90)=149.22µs p(95)=178.66µs
p(99)=313.97µs p(99.9)=1.34ms p(99.99)=3.34ms max=11.66ms
http_req_failed................: 0.00% ✓ 0 ✗ 2862736
http_req_receiving.............: avg=10.27µs min=4.25µs med=8.78µs p(75)=12.08µs p(90)=15.89µs p(95)=18.82µs
p(99)=27.24µs p(99.9)=42.35µs p(99.99)=69.13µs max=5.26ms
http_req_sending...............: avg=2.98µs min=1.61µs med=2.49µs p(75)=3.47µs p(90)=4.54µs p(95)=5.34µs
p(99)=7.05µs p(99.9)=14.07µs p(99.99)=25.94µs max=912.98µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s p(75)=0s p(90)=0s p(95)=0s
p(99)=0s p(99.9)=0s p(99.99)=0s max=0s
http_req_waiting...............: avg=100.54µs min=51.32µs med=88.12µs p(75)=106.22µs p(90)=133.02µs p(95)=161.41µs
p(99)=287.89µs p(99.9)=1.31ms p(99.99)=3.27ms max=11.63ms
http_reqs......................: 2862736 6816.037544/s
iteration_duration.............: avg=143.9µs min=79.09µs med=130.53µs p(75)=153.91µs p(90)=186.1µs p(95)=216.42µs
p(99)=354.75µs p(99.9)=1.4ms p(99.99)=3.5ms max=11.71ms
Copyright 2024 Matthew Willer. Available for redistribution and use under the BSD 3-Clause License
FHIR® is the registered trademark of Health Level Seven International and the use does not constitute endorsement by HL7