From 9255df8cfa0caf2e6dca8a5129f78131a1fdda8d Mon Sep 17 00:00:00 2001 From: Martin Ndegwa Date: Tue, 24 Sep 2024 12:09:20 +0300 Subject: [PATCH 1/2] Add a SyncJobStatus result callback amid Sync retries --- .../android/fhir/sync/FhirSyncWorker.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt b/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt index afb43458be..d37bee39ee 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt @@ -21,6 +21,7 @@ import androidx.work.CoroutineWorker import androidx.work.Data import androidx.work.WorkerParameters import androidx.work.workDataOf +import ca.uhn.fhir.context.FhirContext import com.google.android.fhir.FhirEngine import com.google.android.fhir.FhirEngineProvider import com.google.android.fhir.OffsetDateTimeTypeAdapter @@ -32,11 +33,15 @@ import com.google.android.fhir.sync.upload.request.UploadRequestGeneratorFactory import com.google.gson.ExclusionStrategy import com.google.gson.FieldAttributes import com.google.gson.GsonBuilder +import java.nio.charset.StandardCharsets import java.time.OffsetDateTime import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel import kotlinx.coroutines.launch +import org.apache.commons.io.IOUtils +import org.hl7.fhir.r4.model.OperationOutcome +import retrofit2.HttpException import timber.log.Timber /** @@ -135,6 +140,8 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter } val result = synchronizer.synchronize() + if (result is SyncJobStatus.Failed) onFailedSyncJobResult(result) + val output = buildWorkData(result) // await/join is needed to collect states completely @@ -155,6 +162,34 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter } } + open fun onFailedSyncJobResult(failedSyncJobStatus: SyncJobStatus.Failed) { + try { + val jsonParser = FhirContext.forR4().newJsonParser() + val exceptions = (failedSyncJobStatus).exceptions + + exceptions.forEach { resourceSyncException -> + val operationOutcome = + jsonParser.parseResource( + IOUtils.toString( + (resourceSyncException.exception as HttpException) + .response() + ?.errorBody() + ?.byteStream(), + StandardCharsets.UTF_8, + ), + ) as OperationOutcome + + operationOutcome.issue.forEach { operationOutcomeIssueComponent -> + Timber.e( + "SERVER ${operationOutcomeIssueComponent.severity} - HTTP ${resourceSyncException.exception.code()} | Code - ${operationOutcomeIssueComponent.code} | Diagnostics - ${operationOutcomeIssueComponent.diagnostics}", + ) + } + } + } catch (e: Exception) { + Timber.e(e) + } + } + private fun buildWorkData(state: SyncJobStatus): Data { return workDataOf( // send serialized state and type so that consumer can convert it back From b519c23990fbb7f6ebda67b61f836fd61343b464 Mon Sep 17 00:00:00 2001 From: Martin Ndegwa Date: Wed, 9 Oct 2024 18:39:04 +0300 Subject: [PATCH 2/2] Error handling logic for non OperationOutcome errors --- .../java/com/google/android/fhir/sync/FhirSyncWorker.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt b/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt index d37bee39ee..0ec3e74672 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt @@ -163,10 +163,10 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter } open fun onFailedSyncJobResult(failedSyncJobStatus: SyncJobStatus.Failed) { - try { - val jsonParser = FhirContext.forR4().newJsonParser() - val exceptions = (failedSyncJobStatus).exceptions + val jsonParser = FhirContext.forR4().newJsonParser() + val exceptions = (failedSyncJobStatus).exceptions + try { exceptions.forEach { resourceSyncException -> val operationOutcome = jsonParser.parseResource( @@ -187,6 +187,7 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter } } catch (e: Exception) { Timber.e(e) + exceptions?.forEach { Timber.e(it.exception.message) } } }