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 148e3f01a7..772fad8348 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 @@ -29,6 +30,7 @@ import com.google.android.fhir.sync.upload.UploaderImpl 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 @@ -36,6 +38,9 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch +import org.apache.commons.io.IOUtils +import org.hl7.fhir.r4.model.OperationOutcome +import retrofit2.HttpException import timber.log.Timber /** A WorkManager Worker that handles periodic sync. */ @@ -91,6 +96,9 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter ) .apply { subscribe(flow) } .synchronize() + + if (result is SyncJobStatus.Failed) onFailedSyncJobResult(result) + val output = buildWorkData(result) // await/join is needed to collect states completely @@ -118,6 +126,33 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter } } + open fun onFailedSyncJobResult(failedSyncJobStatus: SyncJobStatus.Failed) { + try { + CoroutineScope(Dispatchers.IO).launch { + val jsonParser = FhirContext.forR4().newJsonParser() + + (failedSyncJobStatus).exceptions.filterIsInstance().forEach { + resourceSyncHTTPException -> + val operationOutcome = + jsonParser.parseResource( + IOUtils.toString( + resourceSyncHTTPException.response()?.errorBody()?.byteStream(), + StandardCharsets.UTF_8 + ) + ) as OperationOutcome + + operationOutcome.issue.forEach { operationOutcome -> + Timber.e( + "SERVER ${operationOutcome.severity} - HTTP ${resourceSyncHTTPException.code()} | Code - ${operationOutcome.code} | Diagnostics - ${operationOutcome.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