HL7 parser with Kafka streaming support for high-throughput healthcare data processing.
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ HL7 Files │─────>│ File Producer│─────>│ Kafka Topic │─────>│ Consumer │
│ (.hl7) │ │ (Input) │ │ (hl7-raw) │ │ (Parser) │
└─────────────┘ └──────────────┘ └─────────────┘ └──────────────┘
│
v
┌──────────────────┐
│ Kafka Topic │
│ (appointments) │
└──────────────────┘
1. Streaming Architecture
- Kafka-based ingestion handles massive concurrent HL7 file uploads
- Horizontal scaling via consumer groups enables processing millions of messages
- Backpressure handling prevents memory exhaustion
2. Separation of Concerns
- hl7_parser.py: Core parsing logic (segments, messages, domain models)
- hl7_kafka.py: Streaming infrastructure (producers, consumers)
- hl7_cli.py: Command-line interface and file operations
3. Error Handling Strategy
- Invalid messages sent to dead-letter topic (
{output-topic}-errors) - Graceful degradation: missing optional fields don't fail parsing
- Structured exceptions for different failure modes
4. Performance Optimizations
- Thread pool executor for parallel message processing
- Batch commits reduce Kafka overhead
- Configurable batch sizes and worker threads
pip install -r requirements.txtpython hl7_cli.py parse input.hl7
python hl7_cli.py parse input.hl7 -o output.jsonpython hl7_cli.py parse-dir ./hl7_files/
python hl7_cli.py parse-dir ./hl7_files/ -o ./output/Send files to Kafka:
python hl7_cli.py kafka-produce file1.hl7 file2.hl7 \
--bootstrap localhost:9092 \
--topic hl7-rawStart consumer (parse from Kafka):
python hl7_cli.py kafka-consume \
--bootstrap localhost:9092 \
--input-topic hl7-raw \
--output-topic appointments \
--workers 20 \
--batch-size 200MSH|^~\&|EPIC|HOSPITAL|||202505051430||SIU^S12|MSG12346|P|2.3|
SCH|234567||||||Cardiology Follow-up|||45|m|^^45^20250515143000|||||||||D12345^Johnson^Emily|||||BOOKED
PID|1||P23456||Smith^Sarah^Anne||19920315|F|||456 Oak Ave^^Boston^MA^02101
PV1|1|O|Cardiology Unit^Room 105||||D12345^Johnson^
MSH|^~\&|MEDITECH|CLINIC|||202505101000||SIU^S12|MSG12347|P|2.3|
MSH|^~\&|CERNER|MEDICAL_CENTER|||202505121545||SIU^S12|MSG12348|P|2.3|
SCH|456789||||||Orthopedic Surgery Consultation|||90|m|^^90^20250525154500|||||||||D45678^Martinez^Carlos|||||PENDING
PID|1||P45678||Davis^Jennifer^Lynn||19780622|F|||321 Elm Rd^^Austin^TX^78701
PV1|1|O|Orthopedics^Room 301||||D45678^Martinez^Carlos
PV1|1|O|Orthopedics^Room 301||||D45678^Martinez^Carlos
PV1|1|O|Orthopedics^Room 301||||D45678^Martinez^Carlos
MSH|^~\&|DENTRIX|DENTAL_CLINIC|||202505081100||SIU^S12|MSG12349|P|2.3|
SCH|567890||||||Routine Dental Cleaning|||60|m|^^60^20250518110000|||||||||D23456^Lee^Susan|||||BOOKED
PV1|1|O|Dental Suite^Chair 3||||D23456^Lee^Susan
MSH|^~\&|ALLSCRIPTS|DERMATOLOGY|||202505141630||SIU^S12|MSG12350|P|2.3|
SCH|678901||||||Annual Skin Cancer Screening|||30|m|^^30^20250528163000|||||||||D89012^Patel^Anjali|||||WAITLISTED
PID|1||P67890||Anderson^Robert^Lee||19650425|M|||987 Cedar Ln^^Miami^FL^33101
XYZ|1|O|Dermatology^Exam Room 2||||D89012^Patel^Anjali
PV1|1|O|Behavioral Health^Room 410||||D34567^Thompson^David[
{
"appointment_id": "234567",
"appointment_datetime": "2025-05-15T14:30:00Z",
"patient": {
"id": "P23456",
"first_name": "Sarah",
"last_name": "Smith",
"dob": "1992-03-15",
"gender": "F"
},
"provider": {
"id": "D12345",
"name": "Dr. Johnson "
},
"location": "Cardiology Unit Room 105",
"reason": "Cardiology Follow-up"
},
{
"appointment_id": "456789",
"appointment_datetime": "2025-05-25T15:45:00Z",
"patient": {
"id": "P45678",
"first_name": "Jennifer",
"last_name": "Davis",
"dob": "1978-06-22",
"gender": "F"
},
"provider": {
"id": "D45678",
"name": "Dr. Martinez Carlos"
},
"location": "Orthopedics Room 301",
"reason": "Orthopedic Surgery Consultation"
},
{
"appointment_id": "567890",
"appointment_datetime": "2025-05-18T11:00:00Z",
"patient": null,
"provider": {
"id": "D23456",
"name": "Dr. Lee Susan"
},
"location": "Dental Suite Chair 3",
"reason": "Routine Dental Cleaning"
},
{
"appointment_id": "678901",
"appointment_datetime": "2025-05-28T16:30:00Z",
"patient": {
"id": "P67890",
"first_name": "Robert",
"last_name": "Anderson",
"dob": "1965-04-25",
"gender": "M"
},
"provider": {
"id": "D34567",
"name": "Dr. Thompson David"
},
"location": "Behavioral Health Room 410",
"reason": "Annual Skin Cancer Screening"
}
]docker build -t hl7-parser .docker-compose up -dThis starts:
- Zookeeper
- Kafka broker
- HL7 parser consumer
# Run multiple consumer instances
docker-compose up --scale hl7-parser=5- Increase Kafka topic partitions for parallelism
- Each consumer group member processes separate partitions
- Linear scaling up to partition count
# Consumer configuration
max_workers=50 # Thread pool size
batch_size=500 # Messages per batch
max_poll_records=1000 # Kafka poll sizepython -m unittest hl7_unittest.py -v- Valid message parsing
- Missing segment handling
- Timestamp normalization
- Multiple messages per file
- Malformed input handling
- Empty field processing
- MSH: Message header (validation, message type)
- SCH: Scheduling information (appointment ID, datetime, reason)
- PID: Patient demographics (optional but recommended)
- PV1: Visit information (provider, location)
SCH Segment:
- Field 1: Appointment ID
- Field 7: Reason for visit
- Field 11: Appointment datetime (component 4)
- Field 16: Provider information
PID Segment:
- Field 3: Patient ID
- Field 5: Patient name (components: last^first)
- Field 7: Date of birth (YYYYMMDD)
- Field 8: Gender
PV1 Segment:
- Field 3: Location (components: facility^room)
- Field 7: Attending provider
- Messages follow HL7 v2.x conventions (pipe-delimited, carriage return separators)
- SIU^S12 is the only supported message type
- Timestamps are in format YYYYMMDDHHMMSS or YYYYMMDDHHMM
- InvalidMessageTypeError: Non-SIU^S12 messages rejected
- MissingRequiredSegmentError: MSH or SCH missing
- HL7ParsingError: Generic parsing failures
- Failed messages sent to
{output-topic}-errors - Includes error message, offset, and truncated raw data