Ingesting Production Data
- Before starting production ingestion
- Ingestion process
- Organizing data directory
- Selecting Data for Ingestion
- Starting Ingestion Workflow
- Monitoring the workflow progress
- General monitoring tips
- Checking for processing errors
- Monitoring individual log steps
- Verifying data warehouse content
Before starting production ingestion
The data structure (also known as the data model or schema) often changes from year to year. In some cases this might require updating the DSL script. Therefore, it is important before launching the ingestion of the full new data (we refer to it as production ingestion) to test that current script can handle it.
Please refer to Test data ingestion section of the Testing Medicare Processing Workflow page on how to test data ingestion.
Ingestion process
Data directories must be organized in a specific way for ingestion by Dorieh pipelines. Consult the Medicare Pipeline Documentation for more detailed guidance on data placement. Afterward, ensure you have successfully tested smaller sample ingestions as described in the Getting Started guide.
See also General description
Organizing data directory
In the ReD environment, the data currently is hosted in:
/data/labs/dominici_nsaph_l3/import/CMS\ Data\ Request\ DUA\ 19945\ -\ RESDAC-9229/13701_copy/13701/
-- 2015
-- 2019
-- 2020
-- 2021
Selecting Data for Ingestion
-
Single Year Ingestion: To ingest data for a specific year, provide the path with that year's folder, e.g.,
/data/labs/dominici_nsaph_l3/import/CMS\ Data\ Request\ DUA\ 19945\ -\ RESDAC-9229/13701_copy/13701/2015
The folder must contain MBSF and MedPAR
*.datand corresponding*.ftsfiles (see FTS files description). -
Multi-Year Ingestion: To ingest multiple years of data, point to the parent directory:
/data/labs/dominici_nsaph_l3/import/CMS\ Data\ Request\ DUA\ 19945\ -\ RESDAC-9229/13701_copy/13701
(Consult the section above) for the correct directory structure.
In this case, the ingestion for all 4 years (2015, 2019 - 2021) will be triggered.
Starting Ingestion Workflow
The processing of the Medicare data for 20 years takes several days. Even when adding data for a single year, the entire dataset is reprocessed. This happens because the beneficiaries dataset is aggregated across multiple years of enrollment, and therefore must be recalculated in full. Hence, you need to take several precautions before starting the process:
- Ensure the worker node has the capacity to run uninterrupted for at least 7 days. In particular, verify that it will not be terminated earlier because of the end of reservation window.
- Ensure that the process is started using
nohupcommand and with background processing (&at the end of line). - Ensure that the progress is logged into a directory available for monitoring.
We recommend running the process in the
directory. For example, ingestion of 2015 data has been run in
The following command has been used to start the ingestion:
cd /shared/dorieh-logs/ingestion/2015
nohup toil-cwl-runner --retryCount 1 --cleanWorkDir never --outdir outputs --workDir work --jobStore j1 /usr/local/lib/python3.9/site-packages/dorieh/cwl/medicare.cwl --database /home/dorieh/database.ini --connection_name dorieh --input /data/labs/dominici_nsaph_l3/import/CMS\ Data\ Request\ DUA\ 19945\ -\ RESDAC-9229/13701_copy/13701/2015 2>&1 > 1_2015prod.log &
tail -f 1_2015prod.log
The same command split for readability over multiple lines (but might be more difficult to copy and paste):
cd /shared/dorieh-logs/ingestion/2015
nohup toil-cwl-runner --retryCount 1 --cleanWorkDir never --outdir outputs \
--workDir work --jobStore j1 \
/usr/local/lib/python3.9/site-packages/dorieh/cwl/medicare.cwl \
--database /home/dorieh/database.ini \
--connection_name dorieh \
--input /data/labs/dominici_nsaph_l3/import/CMS\ Data\ Request\ DUA\ 19945\ -\ RESDAC-9229/13701_copy/13701/2015 \
2>&1 > 1_2015prod.log &
tail -f 1_2015prod.log
Nohup
Do not forget to use nohup!
Monitoring the workflow progress
General monitoring tips
No need for worker node or Singularity shell
Progress can be monitored from any node without needing to ssh into a worker node. There is also no need to start a singularity shell.
The last command from the previous section will continuously update workflow progress:
To view the log interactively when logging back on the system use:
Successful completion is indicated by JSON entries detailing workflow step progress and error logs that are saved into outputs directory:
{
"qc_ev_create_log": {
"location": "file:///shared/dorieh-logs/ingestion/2015/outputs/data_loader-2025-03-05-09-48-27.log_2",
"basename": "data_loader-2025-03-05-09-48-27.log",
"nameroot": "data_loader-2025-03-05-09-48-27",
"nameext": ".log",
"class": "File",
"checksum": "sha1$fa01481303c9030c8095387661a3bdc6851fc1ed",
"size": 12060,
"path": "/shared/dorieh-logs/ingestion/2015/outputs/data_loader-2025-03-05-09-48-27.log_2"
},
"registry": {
"location": "file:///shared/dorieh-logs/ingestion/2015/outputs/cms.yaml",
"basename": "cms.yaml",
"nameroot": "cms",
"nameext": ".yaml",
"class": "File",
"checksum": "sha1$73700ade239b3a0c5f755ef694f05aebb4442c68",
"size": 140457,
"path": "/shared/dorieh-logs/ingestion/2015/outputs/cms.yaml"
}
}
The workflow has multiple steps and each step produces 2 log entries: a progress log and an error log (the latter should be an empty file), so there many entries like above. Corresponding files are saved into the output directory (defined as a --outdir command line argument).
Above the outputs there will be messages like:
[2025-03-05T11:59:10+0000] [MainThread] [I] [toil.leader] Finished toil run successfully.
[2025-03-05T11:59:10+0000] [MainThread] [I] [toil.cwl.cwltoil] Collecting workflow outputs...
[2025-03-05T11:59:10+0000] [MainThread] [I] [toil.cwl.cwltoil] Saving file:///shared/dorieh-logs/ingestion/2015/outputs/create_admissions.err...
...
[2025-03-05T11:59:13+0000] [MainThread] [I] [toil.cwl.cwltoil] Stored workflow outputs
[2025-03-05T11:59:13+0000] [MainThread] [I] [toil.cwl.cwltoil] Computing output file checksums...
[2025-03-05T11:59:13+0000] [MainThread] [I] [toil.cwl.cwltoil] CWL run complete!
[2025-03-05T11:59:19+0000] [MainThread] [I] [toil.common] Successfully deleted the job store: FileJobStore(/shared/dorieh-logs/ingestion/2015/j1)
You can also grep for Finished toil run successfully or CWL run complete!:
If the workflow has failed, the last line of the log file will indicate PermanentFail message. However, sometimes, if the failure was caused by OS killing the process or the node termination, the failure message might be absent. If you suspect that something is wrong, check for the timestamp last update message in the log file or for the timestamp of the log file itself. If it is more than several hours old, it is an indication that workflow is no longer running.
Long running steps...
Some steps — particularly those involving in-database transformations — may take considerable time and generate minimal log output.
To obtain more information you can examine log files for individual steps, especially those that are currently running. Toil produces a bit funny directory structure, so we need to use a few tricks to find the logs for currently running workflow steps.
Checking for processing errors
The following command will let you see if you have any errors:
If the output is empty, it is a good sign - no errors.
Log files on success
In a successful run, most error log files should either be empty files. If you find non-empty .err files, examine them closely.
If you have multiple runs inside your work directory, you can provide a subdirectory for the current run, e.g.:
find /shared/dorieh-logs/ingestion/2015/work//toilwf-c36b795b68935d99be01ed1556c85b1e/ -type f -name "*.err" -size +0c -exec ls -alF {} \;
Finally, to see all error logs just remove -size +0c filter:
find /shared/dorieh-logs/ingestion/2015/work/toilwf-c36b795b68935d99be01ed1556c85b1e/ -type f -name "*.err" -exec ls -alF {} \;
Monitoring individual log steps
First, search for all log files:
find /shared/dorieh-logs/ingestion/2015/work/toilwf-c36b795b68935d99be01ed1556c85b1e/ -type f -name "*.log" -exec ls -alF {} \;
Working directories have random names
Be sure to replace directory name toilwf-c36b795b68935d99be01ed1556c85b1e with the one corresponding to the current run.
Look for the most recent log files. Then examine them.
Verifying data warehouse content
Database access is only available from a singularity shell on a worker node
Checking database content can only be performed from a worker node in dorieh partition and inside a Singularity shell (Apptainer> prompt)
Inside the Singularity shell, run the following queries to ensure that the relevant tables have been updated:
python -m dorieh.platform.util.psql --connection dorieh --db /home/dorieh/database.ini "SELECT obj_description(oid) AS comment FROM pg_class WHERE relname = 'mbsf_abcd_2015'"
python -m dorieh.platform.util.psql --connection dorieh --db /home/dorieh/database.ini "SELECT obj_description(oid) AS comment FROM pg_class WHERE relname = 'beneficiaries'"
python -m dorieh.platform.util.psql --connection dorieh --db /home/dorieh/database.ini "SELECT obj_description(oid) AS comment FROM pg_class WHERE relname = 'enrollments'"
python -m dorieh.platform.util.psql --connection dorieh --db /home/dorieh/database.ini "SELECT obj_description(oid) AS comment FROM pg_class WHERE relname = 'admissions'"
The output should look like:
('CREATED BY Dorieh: {"version": "0.2.5", "url": "https://github.com/NSAPH-Data-Platform/dorieh", "commit": null}. Created at 2025-02-25 23:59:18.116167',)
('CREATED BY Dorieh: {"version": "0.2.5", "url": "https://github.com/NSAPH-Data-Platform/dorieh", "commit": null}. Created at 2025-02-28 10:25:52.848707',)
...
You can compare the timestamp with the start time of your ingestion job to confirm these updates occurred during the current run.
Note
📎 Timestamps shown here are illustrative. You should see values corresponding to your current run.
Then, see how many records we now have in the data warehouse, partitioning by year:
python -m dorieh.platform.util.psql --connection dorieh --db /home/dorieh/database.ini 'SELECT count(*) from medicare.beneficiaries '
python -m dorieh.platform.util.psql --connection dorieh --db /home/dorieh/database.ini 'SELECT year, count(*) from medicare.enrollments GROUP BY year order by year'
python -m dorieh.platform.util.psql --connection dorieh --db /home/dorieh/database.ini 'SELECT year, count(*) from medicare.admissions GROUP BY year order by year'
You can also examine admissions audit table to verify the number of rejected records increased where expected.