-
Notifications
You must be signed in to change notification settings - Fork 93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support fetching resources with same parent table #144 #146
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @mozzy11; this looks good. I just have two suggestions.
@@ -180,8 +180,8 @@ public Integer fetchMaxId(String tableName) throws SQLException { | |||
for (String search : searchList) { | |||
if (linkTemplate.containsKey("fhir") && linkTemplate.get("fhir") != null) { | |||
String[] resourceName = linkTemplate.get("fhir").split("/"); | |||
if (resourceName.length >= 1 && resourceName[1].equals(search)) { | |||
reverseMap.put(entry.getValue().getParentTable(), resourceName[1]); | |||
if (resourceName.length >= 1 && resourceName[1].equals(search) && entry.getValue().isEnabled()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: drop isEnabled
condition here and add a check before reverseMap.put
to throw an exception if reverseMap
already has an entry with the same key. This way we can fail fast for mis-configured resource mapping files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -91,7 +92,14 @@ public MethodOutcome uploadResource(Resource resource) { | |||
interceptors = Collections.singleton(new BasicAuthInterceptor(sinkUsername, sinkPassword)); | |||
} | |||
|
|||
return uploadBundle(sinkUrl, bundle, interceptors); | |||
Collection<MethodOutcome> responses; | |||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bashir2 , the reason for doing this ,
the pipeline was failing with an error ResourceVersionConflictException : Multiple client threads trying to create resources with similar self assigned ID
, but on rerunning it again ,it could work.
i think two threads try to create a person and patient resource with the same uuid ,and hapi throws the error.
so what i did here is to catch the exception and re-upload the bundle . so one bundle ie person is uploaded first and then the patient, without conflicting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @kimaina
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So as we discussed on Tuesday, I think we should get to the bottom of this. Assuming that your sink FHIR store is a HAPI FHIR server (JPA), I don't think creating two different resource types (e.g., Patient and Person) with the same ID should cause a problem.
Codecov Report
@@ Coverage Diff @@
## master #146 +/- ##
============================================
+ Coverage 42.37% 42.76% +0.39%
- Complexity 96 97 +1
============================================
Files 21 21
Lines 767 774 +7
Branches 65 67 +2
============================================
+ Hits 325 331 +6
- Misses 420 421 +1
Partials 22 22
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @mozzy11 for the changes but I think a new bug has been introduced now.
utils/dbz_event_to_fhir_config.json
Outdated
@@ -204,8 +204,7 @@ | |||
"title": "Visit", | |||
"parentTable": "visit", | |||
"linkTemplates": { | |||
"rest": "/ws/rest/v1/visit/{uuid}?v=full", | |||
"fhir": "/Encounter/{uuid}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you have removed this line because of the exception at line JdbcFetchUtil.java line 188, is that correct? The problem is that the mapping here is valid and we want to keep it. Think about the other use of this config: When there is a change in the visit
table captured by Debezium, we want to fetch the corresponding Encounter resource hence we need to keep this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ya sure corrected it
@@ -91,7 +92,14 @@ public MethodOutcome uploadResource(Resource resource) { | |||
interceptors = Collections.singleton(new BasicAuthInterceptor(sinkUsername, sinkPassword)); | |||
} | |||
|
|||
return uploadBundle(sinkUrl, bundle, interceptors); | |||
Collection<MethodOutcome> responses; | |||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So as we discussed on Tuesday, I think we should get to the bottom of this. Assuming that your sink FHIR store is a HAPI FHIR server (JPA), I don't think creating two different resource types (e.g., Patient and Person) with the same ID should cause a problem.
if (!reverseMap.containsKey(resourceName[1])) { | ||
reverseMap.put(resourceName[1], entry.getValue().getParentTable()); | ||
} else { | ||
log.error("Some tables are mapped to the same Resources"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I have commented in the dbz_event_to_fhir_config.json
below, this is actually not an error but a valid scenario. For example visit
and encounter
tables are both mapped to the Encounter
FHIR resource and this is valid (and needed).
Here is my suggestion with two examples for Patient and Encounter:
- Parse the config and for each FHIR resource, find the list of parent tables that are relevant for that resource, e.g., the map would be:
Patient->person
andEncounter->encounter,visit
- In the main pipeline (that uses this reverse-map), for each FHIR resource, fetch all IDs from all tables in its list. So for
Patient
all IDs ofperson
and forEncounter
all IDs of bothencounter
andvisit
. - For the list of IDs found above, ask the FHIR module to give those resources, e.g., for all
encounter
andvisit
IDs requestEncounter/ID
.
If this is not clear or you see any problems, please let me know. Otherwise let's merge both these reverse-map methods and create one like above.
This is important to be fixed (since otherwise it is a functionality bug) but if fixing this and also addressing my previous comment about fetching IDs only once from each table is difficult, please feel free not to address that issue in this PR and instead file a separate issue for it. So you may end up with Person->person
and Patient->person
maps and get the person
IDs twice from the DB (which can be avoided but that is fine to leave for future).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
return reverseMap; | ||
} | ||
} | ||
|
||
public Map<String, ArrayList<String>> deduplicateReverseMap(Map<String, String> reverseMap) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to separate public methods for creation of reverse-map. Please expose only one of these and directly use that in FhirEtl.
assertEquals(4, reverseMap.size()); | ||
assertEquals(reverseMap.get("Patient"), "person"); | ||
assertEquals(reverseMap.get("Person"), "person"); | ||
assertEquals(reverseMap.get("Encounter"), "encounter"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So specifically here, Encounter
should be mapped to both encounter
and visit
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corrected in the new commit
@bashir2 , regarding the issue of HAPI -FHIR , innitially i was running against a new version of HAPI with customized configs. I think we should file another ticket for that specifically. Otherwise i think the new commit addreses the issue of fetching resources with same parent table and also not re-fetching the max id for resources with the same parent table |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (Map.Entry<String, EventConfiguration> entry : tableToFhirMap.entrySet()) { | ||
Map<String, String> linkTemplate = entry.getValue().getLinkTemplates(); | ||
for (String search : searchList) { | ||
if (linkTemplate.containsKey("fhir") && linkTemplate.get("fhir") != null) { | ||
String[] resourceName = linkTemplate.get("fhir").split("/"); | ||
ArrayList<String> resources = new ArrayList<String>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this to line 191 (i.e., the else
section).
} | ||
reverseMap.put(entry.getValue().getParentTable(), resources); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this to line 191 as well (i.e., the else
section). In the other case that the map already contains the parent table name, we don't need to create a new list and/or add it to the map. We just need to update the current list in the map.
Thanks @bashir2 , the unit tests pass suceesfuly here . its the e2e tests that fails wilh |
cc @bashir2 i have done the clean up |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @mozzy11 this looks good. I just added some cosmetic changes.
Description of what I changed
Fixes #144
E2E test
TESTED:
mvn compile exec:java -pl batch
-Dexec.args="--openmrsServerUrl=http://localhost:8081/openmrs
--openmrsUserName=admin --openmrsPassword=Admin123
--fhirSinkPath=http://localhost:8080/fhir
--sinkUserName=hapi --sinkPassword=hapi123
--searchList=Patient,Person --batchSize=20
--jdbcModeEnabled=true --jdbcUrl=jdbc:mysql://localhost:3306/openmrs
--dbUser=root --dbPassword=Admin123 --jdbcMaxPoolSize=50
--jdbcDriverClass=com.mysql.cj.jdbc.Driver"
Checklist: I completed these to help reviewers :)
My IDE is configured to follow the code style of this project.
No? Unsure? -> configure your IDE, format the code and add the changes with
git add . && git commit --amend
I am familiar with Google Style Guides for the language I have coded in.
No? Please take some time and review Java and Python style guides. Note, when in conflict, OpenMRS style guide overrules.
I have added tests to cover my changes. (If you refactored existing code that was well tested you do not have to add tests)
No? -> write tests and add them to this commit
git add . && git commit --amend
I ran
mvn clean package
right before creating this pull request and added all formatting changes to my commit.All new and existing tests passed.
No? -> figure out why and add the fix to your commit. It is your responsibility to make sure your code works.
My pull request is based on the latest changes of the master branch.
No? Unsure? -> execute command
git pull --rebase upstream master