Skip to content

Commit

Permalink
Implement Job History in Admin API
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderkiel committed Oct 28, 2024
1 parent 75f8e1c commit 1c888e0
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 34 deletions.
10 changes: 10 additions & 0 deletions .github/scripts/admin-api/async-job.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,13 @@ output_expr() {
PROCESSING_DURATION="$(echo "$JOB" | jq "$(output_expr "processing-duration") | .valueQuantity")"
test "processing-duration unit system" "$(echo "$PROCESSING_DURATION" | jq -r .system)" "http://unitsofmeasure.org"
test "processing-duration unit code" "$(echo "$PROCESSING_DURATION" | jq -r .code)" "s"

# History
JOB_HISTORY=$(curl -s -H 'Accept: application/fhir+json' "$BASE/__admin/Task/$JOB_ID/_history")

test "history resource type" "$(echo "$JOB_HISTORY" | jq -r '.resourceType')" "Bundle"
test "history bundle type" "$(echo "$JOB_HISTORY" | jq -r '.type')" "history"
test "history total" "$(echo "$JOB_HISTORY" | jq -r '.total')" "3"
test "history 0 status" "$(echo "$JOB_HISTORY" | jq -r '.entry[0].resource.status')" "completed"
test "history 1 status" "$(echo "$JOB_HISTORY" | jq -r '.entry[1].resource.status')" "in-progress"
test "history 2 status" "$(echo "$JOB_HISTORY" | jq -r '.entry[2].resource.status')" "ready"
20 changes: 15 additions & 5 deletions modules/admin-api/src/blaze/admin_api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
[blaze.middleware.fhir.db :as db]
[blaze.middleware.fhir.output :as fhir-output]
[blaze.middleware.fhir.resource :as resource]
[blaze.middleware.link-headers :as link-headers]
[blaze.middleware.output :as output]
[blaze.module :as m]
[blaze.spec]
Expand Down Expand Up @@ -178,6 +179,10 @@
{:name :resource
:wrap resource/wrap-resource})

(def ^:private wrap-link-headers
{:name :link-headers
:wrap link-headers/wrap-link-headers})

(def ^:private allowed-profiles
#{#fhir/canonical"https://samply.github.io/blaze/fhir/StructureDefinition/ReIndexJob"
#fhir/canonical"https://samply.github.io/blaze/fhir/StructureDefinition/CompactJob"
Expand Down Expand Up @@ -233,9 +238,9 @@

(defn- router
[{:keys [context-path admin-node validator db-sync-timeout dbs
create-job-handler read-job-handler search-type-job-handler
pause-job-handler resume-job-handler cancel-job-handler
cql-cache-stats-handler cql-bloom-filters-handler]
create-job-handler read-job-handler history-job-handler
search-type-job-handler pause-job-handler resume-job-handler
cancel-job-handler cql-cache-stats-handler cql-bloom-filters-handler]
:or {context-path ""
db-sync-timeout 10000}
:as context}]
Expand Down Expand Up @@ -400,6 +405,11 @@
{:get
{:middleware [[wrap-db admin-node db-sync-timeout]]
:handler read-job-handler}}]
["/_history"
{:get
{:middleware [[wrap-db admin-node db-sync-timeout]
wrap-link-headers]
:handler history-job-handler}}]
["/$pause"
{:post
{:handler pause-job-handler}}]
Expand Down Expand Up @@ -533,8 +543,8 @@

(defmethod m/pre-init-spec :blaze/admin-api [_]
(s/keys :req-un [:blaze/context-path ::admin-node :blaze/job-scheduler
::read-job-handler ::search-type-job-handler
::settings ::features]
::read-job-handler ::history-job-handler
::search-type-job-handler ::settings ::features]
:opt [::dbs ::expr/cache ::db-sync-timeout]))

(defmethod ig/init-key :blaze/admin-api
Expand Down
3 changes: 3 additions & 0 deletions modules/admin-api/src/blaze/admin_api/spec.clj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
(s/def ::admin-api/read-job-handler
fn?)

(s/def ::admin-api/history-job-handler
fn?)

(s/def ::admin-api/search-type-job-handler
fn?)

Expand Down
100 changes: 75 additions & 25 deletions modules/admin-api/test/blaze/admin_api_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
[blaze.fhir.spec.type :as type]
[blaze.fhir.test-util :refer [structure-definition-repo]]
[blaze.interaction.create]
[blaze.interaction.history.instance]
[blaze.interaction.read]
[blaze.interaction.search-type]
[blaze.job-scheduler :as js]
Expand Down Expand Up @@ -178,6 +179,7 @@
:admin-node (ig/ref :blaze.db.admin/node)
:job-scheduler (ig/ref :blaze/job-scheduler)
:read-job-handler (ig/ref :blaze.interaction/read)
:history-job-handler (ig/ref :blaze.interaction.history/instance)
:search-type-job-handler (ig/ref :blaze.interaction/search-type)
:dbs {"index" (ig/ref :blaze.db.main/index-kv-store)
"resource" (ig/ref :blaze.db/resource-kv-store)}
Expand All @@ -198,6 +200,11 @@

:blaze.interaction/read {}

:blaze.interaction.history/instance
{:clock (ig/ref :blaze.test/fixed-clock)
:rng-fn (ig/ref :blaze.test/fixed-rng-fn)
:page-id-cipher (ig/ref :blaze.test/page-id-cipher)}

:blaze.interaction/search-type
{:clock (ig/ref :blaze.test/fixed-clock)
:rng-fn (ig/ref :blaze.test/fixed-rng-fn)
Expand Down Expand Up @@ -232,9 +239,10 @@
[:cause-data ::s/problems 1 :pred] := `(fn ~'[%] (contains? ~'% :admin-node))
[:cause-data ::s/problems 2 :pred] := `(fn ~'[%] (contains? ~'% :job-scheduler))
[:cause-data ::s/problems 3 :pred] := `(fn ~'[%] (contains? ~'% :read-job-handler))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :settings))
[:cause-data ::s/problems 6 :pred] := `(fn ~'[%] (contains? ~'% :features))))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :history-job-handler))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 6 :pred] := `(fn ~'[%] (contains? ~'% :settings))
[:cause-data ::s/problems 7 :pred] := `(fn ~'[%] (contains? ~'% :features))))

(testing "invalid context path"
(given-thrown (ig/init {:blaze/admin-api {:context-path ::invalid}})
Expand All @@ -243,12 +251,13 @@
[:cause-data ::s/problems 0 :pred] := `(fn ~'[%] (contains? ~'% :admin-node))
[:cause-data ::s/problems 1 :pred] := `(fn ~'[%] (contains? ~'% :job-scheduler))
[:cause-data ::s/problems 2 :pred] := `(fn ~'[%] (contains? ~'% :read-job-handler))
[:cause-data ::s/problems 3 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :settings))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :features))
[:cause-data ::s/problems 6 :via] := [:blaze/context-path]
[:cause-data ::s/problems 6 :pred] := `string?
[:cause-data ::s/problems 6 :val] := ::invalid))
[:cause-data ::s/problems 3 :pred] := `(fn ~'[%] (contains? ~'% :history-job-handler))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :settings))
[:cause-data ::s/problems 6 :pred] := `(fn ~'[%] (contains? ~'% :features))
[:cause-data ::s/problems 7 :via] := [:blaze/context-path]
[:cause-data ::s/problems 7 :pred] := `string?
[:cause-data ::s/problems 7 :val] := ::invalid))

(testing "invalid admin node"
(given-thrown (ig/init {:blaze/admin-api {:admin-node ::invalid}})
Expand All @@ -257,12 +266,13 @@
[:cause-data ::s/problems 0 :pred] := `(fn ~'[%] (contains? ~'% :context-path))
[:cause-data ::s/problems 1 :pred] := `(fn ~'[%] (contains? ~'% :job-scheduler))
[:cause-data ::s/problems 2 :pred] := `(fn ~'[%] (contains? ~'% :read-job-handler))
[:cause-data ::s/problems 3 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :settings))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :features))
[:cause-data ::s/problems 6 :via] := [:blaze.db/node]
[:cause-data ::s/problems 6 :pred] := `node?
[:cause-data ::s/problems 6 :val] := ::invalid))
[:cause-data ::s/problems 3 :pred] := `(fn ~'[%] (contains? ~'% :history-job-handler))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :settings))
[:cause-data ::s/problems 6 :pred] := `(fn ~'[%] (contains? ~'% :features))
[:cause-data ::s/problems 7 :via] := [:blaze.db/node]
[:cause-data ::s/problems 7 :pred] := `node?
[:cause-data ::s/problems 7 :val] := ::invalid))

(testing "invalid settings"
(given-thrown (ig/init {:blaze/admin-api {:settings ::invalid}})
Expand All @@ -272,11 +282,12 @@
[:cause-data ::s/problems 1 :pred] := `(fn ~'[%] (contains? ~'% :admin-node))
[:cause-data ::s/problems 2 :pred] := `(fn ~'[%] (contains? ~'% :job-scheduler))
[:cause-data ::s/problems 3 :pred] := `(fn ~'[%] (contains? ~'% :read-job-handler))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :features))
[:cause-data ::s/problems 6 :via] := [::admin-api/settings]
[:cause-data ::s/problems 6 :pred] := `coll?
[:cause-data ::s/problems 6 :val] := ::invalid))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :history-job-handler))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 6 :pred] := `(fn ~'[%] (contains? ~'% :features))
[:cause-data ::s/problems 7 :via] := [::admin-api/settings]
[:cause-data ::s/problems 7 :pred] := `coll?
[:cause-data ::s/problems 7 :val] := ::invalid))

(testing "invalid features"
(given-thrown (ig/init {:blaze/admin-api {:features ::invalid}})
Expand All @@ -286,11 +297,12 @@
[:cause-data ::s/problems 1 :pred] := `(fn ~'[%] (contains? ~'% :admin-node))
[:cause-data ::s/problems 2 :pred] := `(fn ~'[%] (contains? ~'% :job-scheduler))
[:cause-data ::s/problems 3 :pred] := `(fn ~'[%] (contains? ~'% :read-job-handler))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :settings))
[:cause-data ::s/problems 6 :via] := [::admin-api/features]
[:cause-data ::s/problems 6 :pred] := `coll?
[:cause-data ::s/problems 6 :val] := ::invalid))
[:cause-data ::s/problems 4 :pred] := `(fn ~'[%] (contains? ~'% :history-job-handler))
[:cause-data ::s/problems 5 :pred] := `(fn ~'[%] (contains? ~'% :search-type-job-handler))
[:cause-data ::s/problems 6 :pred] := `(fn ~'[%] (contains? ~'% :settings))
[:cause-data ::s/problems 7 :via] := [::admin-api/features]
[:cause-data ::s/problems 7 :pred] := `coll?
[:cause-data ::s/problems 7 :val] := ::invalid))

(testing "with minimal config"
(with-system [{handler :blaze/admin-api} (config (new-temp-dir!))]
Expand Down Expand Up @@ -874,6 +886,44 @@
["issue" 0 "code"] := "not-found"
["issue" 0 "diagnostics"] := "Resource `Task/AAAAAAAAAAAAAAAA` was not found.")))))

(deftest history-job-test
(testing "existing job"
(with-handler [handler] (config (new-temp-dir!)) []
@(handler
{:request-method :post
:uri "/fhir/__admin/Task"
:headers {"content-type" "application/fhir+json"}
:body (fhir-spec/unform-json re-index-job)})

(let [{:keys [status body]}
@(handler
{:request-method :get
:uri "/fhir/__admin/Task/AAAAAAAAAAAAAAAA/_history"})]

(is (= 200 status))

(given body
"resourceType" := "Bundle"
"type" := "history"
["entry" 0 "request" "method"] := "POST"
["entry" 0 "request" "url"] := "Task"
["entry" 0 "resource" "id"] := "AAAAAAAAAAAAAAAA"))))

(testing "non-existing job"
(with-handler [handler] (config (new-temp-dir!)) []
(let [{:keys [status body]}
@(handler
{:request-method :get
:uri "/fhir/__admin/Task/AAAAAAAAAAAAAAAA/_history"})]

(is (= 404 status))

(given body
"resourceType" := "OperationOutcome"
["issue" 0 "severity"] := "error"
["issue" 0 "code"] := "not-found"
["issue" 0 "diagnostics"] := "Resource `Task/AAAAAAAAAAAAAAAA` was not found.")))))

(deftest search-jobs-test
(with-handler [handler] (config (new-temp-dir!)) []
@(handler
Expand Down
2 changes: 1 addition & 1 deletion modules/rest-api/src/blaze/rest_api/routes.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
[blaze.middleware.fhir.error :as error]
[blaze.middleware.fhir.output :as fhir-output]
[blaze.middleware.fhir.resource :as resource]
[blaze.middleware.link-headers :as link-headers]
[blaze.middleware.output :as output]
[blaze.rest-api.middleware.auth-guard :as auth-guard]
[blaze.rest-api.middleware.ensure-form-body :as ensure-form-body]
[blaze.rest-api.middleware.forwarded :as forwarded]
[blaze.rest-api.middleware.link-headers :as link-headers]
[blaze.rest-api.middleware.metrics :as metrics]
[blaze.rest-api.middleware.sync :as sync]
[blaze.rest-api.operation :as-alias operation]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(ns blaze.rest-api.middleware.link-headers
(ns blaze.middleware.link-headers
"Middleware that will transfer bundle links into link headers according to
RFC 8288."
(:require
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ns blaze.rest-api.middleware.link-headers-test
(ns blaze.middleware.link-headers-test
(:require
[blaze.async.comp :as ac]
[blaze.rest-api.middleware.link-headers :refer [wrap-link-headers]]
[blaze.middleware.link-headers :refer [wrap-link-headers]]
[blaze.test-util :as tu]
[clojure.spec.test.alpha :as st]
[clojure.test :as test :refer [deftest testing]]
Expand Down
1 change: 1 addition & 0 deletions resources/blaze.edn
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@
:job-scheduler #blaze/ref :blaze/job-scheduler
:db-sync-timeout #blaze/cfg ["DB_SYNC_TIMEOUT" pos-int? 10000]
:read-job-handler #blaze/ref :blaze.interaction/read
:history-job-handler #blaze/ref :blaze.interaction.history/instance
:search-type-job-handler #blaze/ref :blaze.interaction/search-type}

;;
Expand Down

0 comments on commit 1c888e0

Please sign in to comment.