multiwoven-integrations 0.40.0 → 0.40.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d02ac40ce23d00833bf9387f1363d3f871c0abdfb500c235e3d44a37110c9d8f
|
|
4
|
+
data.tar.gz: e76e2c81bf09fc64962b2639addb8d11ff7d9ad37a38c88b1267e0778d77bd95
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2bf4882833f8c7e2f823b0077b3a4402d78f5c6acbdee0dc068063dd0be1310b0005c3f73305f26389e4bbf34d17ed6011aa6251852dfc0b17a7956a2928bba2
|
|
7
|
+
data.tar.gz: d460e9bd2b1e2b26fff0c1dd33148952c5f8f1d241cb208bc4da5c4cefbdd9e33b16e6e90ecc449c8e1ddd047b2a40c718dcb51f20aa0b7a9e4d61e21f301229
|
|
@@ -8,6 +8,7 @@ module Multiwoven::Integrations::Source
|
|
|
8
8
|
NDJSON_ACCEPT = "application/fhir+ndjson"
|
|
9
9
|
DEFAULT_EXPORT_POLL_INTERVAL = 5
|
|
10
10
|
DEFAULT_EXPORT_TIMEOUT = 120
|
|
11
|
+
CONCURRENT_EXPORT_MESSAGE = "Another request for this same Client and Group is in progress."
|
|
11
12
|
REQUIRED_CONFIG_KEYS = %w[fhir_base_url token_url client_id private_key kid export_group_id].freeze
|
|
12
13
|
DEFAULT_RESOURCES = %w[
|
|
13
14
|
AllergyIntolerance
|
|
@@ -203,36 +204,68 @@ module Multiwoven::Integrations::Source
|
|
|
203
204
|
end
|
|
204
205
|
|
|
205
206
|
def run_bulk_export(connection_config, resource_type)
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
deadline = Time.now + export_timeout(connection_config)
|
|
208
|
+
status_url = kickoff_bulk_export(connection_config, resource_type, deadline: deadline)
|
|
209
|
+
poll_bulk_export(connection_config, status_url, deadline: deadline)
|
|
208
210
|
end
|
|
209
211
|
|
|
210
|
-
def kickoff_bulk_export(connection_config, resource_type)
|
|
212
|
+
def kickoff_bulk_export(connection_config, resource_type, deadline:)
|
|
211
213
|
url = bulk_export_url(connection_config, resource_type)
|
|
212
|
-
response = fhir_get(connection_config, url, extra_headers: { "Prefer" => "respond-async" })
|
|
213
|
-
raise fhir_api_error(response, url) unless response.code.to_s == "202"
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
|
|
215
|
+
loop do
|
|
216
|
+
response = fhir_get(connection_config, url, extra_headers: { "Prefer" => "respond-async" })
|
|
217
|
+
if response.code.to_s == "202"
|
|
218
|
+
status_url = response["content-location"].presence
|
|
219
|
+
raise StandardError, "Epic FHIR 202 #{url} missing Content-Location header" if status_url.nil?
|
|
217
220
|
|
|
218
|
-
|
|
219
|
-
|
|
221
|
+
return status_url
|
|
222
|
+
end
|
|
220
223
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
+
raise fhir_api_error(response, url) unless concurrent_export?(response)
|
|
225
|
+
raise concurrent_export_timeout_error unless wait_for_retry?(connection_config, response, deadline)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
224
228
|
|
|
229
|
+
def poll_bulk_export(connection_config, status_url, deadline:)
|
|
225
230
|
loop do
|
|
226
231
|
response = fhir_get(connection_config, status_url)
|
|
227
232
|
code = response.code.to_s
|
|
228
233
|
return JSON.parse(response.body) if code == "200"
|
|
229
234
|
raise fhir_api_error(response, status_url) unless code == "202"
|
|
230
|
-
raise StandardError, "Epic FHIR 202 #{status_url} still in progress after #{timeout}s" if Time.now >= deadline
|
|
231
235
|
|
|
232
|
-
|
|
236
|
+
unless wait_for_retry?(connection_config, response, deadline)
|
|
237
|
+
raise StandardError,
|
|
238
|
+
"Epic FHIR 202 #{status_url} still in progress after #{export_timeout(connection_config)}s"
|
|
239
|
+
end
|
|
233
240
|
end
|
|
234
241
|
end
|
|
235
242
|
|
|
243
|
+
# Waits between attempts without ever waiting past the shared export
|
|
244
|
+
# deadline: sleeping longer and then retrying would issue a request the
|
|
245
|
+
# caller has already given up on, and Epic counts it as one more
|
|
246
|
+
# concurrent export for this client and group.
|
|
247
|
+
def wait_for_retry?(connection_config, response, deadline)
|
|
248
|
+
remaining = deadline - Time.now
|
|
249
|
+
return false unless remaining.positive?
|
|
250
|
+
|
|
251
|
+
delay = retry_after(response) || export_poll_interval(connection_config)
|
|
252
|
+
return false if delay > remaining
|
|
253
|
+
|
|
254
|
+
sleep(delay)
|
|
255
|
+
true
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def concurrent_export?(response)
|
|
259
|
+
response.body.to_s.downcase.include?(CONCURRENT_EXPORT_MESSAGE.downcase)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def concurrent_export_timeout_error
|
|
263
|
+
StandardError.new(
|
|
264
|
+
"Epic is still preparing another bulk export for this Client and Group. " \
|
|
265
|
+
"Retry after the existing export completes."
|
|
266
|
+
)
|
|
267
|
+
end
|
|
268
|
+
|
|
236
269
|
def download_bulk_output(connection_config, manifest, resource_type, limit:, offset:)
|
|
237
270
|
return [] if limit&.zero?
|
|
238
271
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: multiwoven-integrations
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.40.
|
|
4
|
+
version: 0.40.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Subin T P
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|