Deep dives into specific back-end technologies which allow for the extension of Qlik to fit the needs of the enterprise.
This is a more in-depth post as a follow up to the overview post: Getting Notified from Qlik Sense
Inside of the Qlik Sense Repository, there is a Notification API endpoint which allows the Repository to do a push notification, in JSON. In this example, we will use it receive a notification on a reload failure, but a more sophisticated example of using this endpoint can be found in the Qlik Sense Event Driven Cross Site App Promoter Repository on the Enterprise Architecture GitHub.
Note: subscriptions created using the Notification API are transient. They will not exist after the Qlik Sense Repository Service restarts. For production integrations, a methodology for polling the Repository to determine whether it has restarted / has the handle will need to be created. In the Qlik Sense Event Driven Cross Site App Promoter project, a NotificationCreator service is used to ensure that the subscription is always present in the Repository Service.
Note: In this post we will use screenshots from Postman since it does a good job of visually displaying the elements of an API call. These calls can be made using any scripting / programming language which can issue RESTful API calls.
When creating a notification handle, there are 3 key params:
The Name param refers to the Repository entity that a change subscription should be configured for. This can be ExecutionResult (when monitoring task progress), App (when monitoring changes to an App), or any path where there is a Repository API (/qrs/path/..).
For a full listing of endpoints which are exposed on your version of Qlik Sense, issue a GET /qrs/about/api/description
API call.
The changeType param refers to the numeric value of the change. The current values as of Qlik Sense September 2018, which were discernible via a GET /qrs/about/openapi/main
call, are:
{
"name": "changetype",
"in": "query",
"required": false,
"default": "Undefined",
"type": "integer",
"allowEmptyValue": true,
"enum": [
0,
1,
2,
3
],
"x-enumNames": [
"Undefined",
"Add",
"Update",
"Delete"
]
}
The filter param is optional, but generally encouraged. For the specific value, a close inspection of the spec for the Name which will be monitored is needed. Since this example is focusing on tasks, the ExecutionResult spec, which is discernible via a GET /qrs/about/openapi/main
call, is as follows:
"ExecutionResult": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"createdDate": {
"type": "string",
"format": "date-time"
},
"modifiedDate": {
"type": "string",
"format": "date-time"
},
"modifiedByUserName": {
"type": "string"
},
"schemaPath": {
"type": "string"
},
"privileges": {
"type": "array",
"items": {
"type": "string"
}
},
"taskID": {
"type": "string",
"format": "uuid"
},
"executionID": {
"type": "string",
"format": "uuid"
},
"appID": {
"type": "string",
"format": "uuid"
},
"executingNodeID": {
"type": "string",
"format": "uuid"
},
"executingNodeName": {
"type": "string"
},
"status": {
"type": "integer",
"enum": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12
],
"x-enumNames": [
"NeverStarted",
"Triggered",
"Started",
"Queued",
"AbortInitiated",
"Aborting",
"Aborted",
"FinishedSuccess",
"FinishedFail",
"Skipped",
"Retry",
"Error",
"Reset"
]
},
"startTime": {
"type": "string",
"format": "date-time"
},
"stopTime": {
"type": "string",
"format": "date-time"
},
"duration": {
"type": "integer",
"format": "milliseconds"
},
"fileReferenceID": {
"type": "string",
"format": "uuid"
},
"scriptLogAvailable": {
"type": "boolean"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/ExecutionResultDetailCondensed"
}
}
},
"x-qlik-stability": "Locked"
}
If we want to monitor on a task which fails due to a script related problem, then the status value that we are interested in is FinishedFail which has a numeric value of 8.
The PropertyName param is also optional. Much like the filter param, you are doing further drill downs. But instead of doing a filter on the entity specified in the Name, you are monitoring changes on the property of the entity without specifying a known value. For example, if you wanted monitor for when an app is published, you can create a subscription with this config:
This will provoke a response when:
For the use of monitoring the pure publish operation, there are other scenarios where you want covered:
To allow for coverage of those scenarios, we can create a subscription with the following config:
A clean distinction between PropertyName and Filter is that PropertyName is a reduction in the monitoring space but without unknown values. In the above scenario, we do not know what the publishTime will be, but merely that we want to monitor for changes in that element of the App’s entity. Filters, on the other hand, require known values.
The condition param likewise is optional. This param allows a script / API call to be issued and handle created only if the condition is fulfilled. When the conditional is not, fulfilled, a null GUID for the handle will be returned:
To continue with the specific work-flow on task failures, for the params section of the POST that we will construct to create the subscription is:
For the headers, we are using standard headers for a QRS API call:
For the body of the POST request, we will wrap a RESTful endpoint in double quotes:
In the 201 response from the Qlik Sense Repository Service we receive the Handle ID of the subscription:
{
"value": "0a950014-61df-44d5-b97f-b911231aa746"
}
Note: Repeated POSTs using the same inputs will return the same handle value
Once this handle is created, our JSON listener receives this style of input on a task failure:
{
"changeType": 2,
"objectType": "ExecutionResult",
"objectID": "783d83ba-436c-475c-993c-fdd0d6f47801",
"changedProperties":
[
"modifiedDate",
"fileReferenceID"
],
"engineID": "",
"engineType": "",
"originatorNodeID": "f206bf30-1e5c-498a-8f73-f1f9e2120863",
"originatorHostName": "QLIKSENSESERVER",
"originatorContextID": None,
"createdDate": "2018-11-01T21:37:33.787Z",
"modifiedDate": "2018-11-01T21:37:34.811Z",
"schemaPath": "ExternalChangeInfo"
}
For a productionalized integration, we’d do a subsequent GET /qrs/executionresult/783d83ba-436c-475c-993c-fdd0d6f47801
call which would return the relevant details like the Task Name / App Name:
{
"id": "783d83ba-436c-475c-993c-fdd0d6f47801",
"createdDate": "2018-11-01T21:37:33.787Z",
"modifiedDate": "2018-11-01T21:37:34.964Z",
"modifiedByUserName": "INTERNAL\\sa_scheduler",
"taskID": "9981ae16-a0fa-466e-a2c2-b8588eafe395",
"executionID": "ef6ca442-ed5c-4df4-a9ad-bb52c339c496",
"appID": "2015e38b-650c-42df-8539-099aa8fef445",
"executingNodeID": "682ddb96-ad29-43b1-89c9-8c25d58ec064",
"executingNodeName": "QlikSENSESERVER",
"status": 8,
"startTime": "2018-11-01T21:37:33.769Z",
"stopTime": "2018-11-01T21:37:34.892Z",
"duration": 1123,
"fileReferenceID": "bf749515-ab2f-42ce-94f9-c698b9c57b42",
"scriptLogAvailable": true,
"details": [
{
"id": "b2987c70-2615-434f-904b-a72e7e8a44bb",
"detailsType": 2,
"message": "Message from ReloadProvider: Reload failed in Engine. Check engine or script logs.",
"detailCreatedDate": "2018-11-01T21:37:34.826Z",
"privileges": null
},
{
"id": "432952f3-6f1f-4b1c-9efe-3e672dca0ed3",
"detailsType": 2,
"message": "Changing task state from Started to FinishedFail",
"detailCreatedDate": "2018-11-01T21:37:34.827Z",
"privileges": null
},
{
"id": "ed2e16ca-781c-44a7-a438-5245e2f23a81",
"detailsType": 2,
"message": "Changing task state from Triggered to Started",
"detailCreatedDate": "2018-11-01T21:37:34.087Z",
"privileges": null
},
{
"id": "990de3de-5d96-4bf9-89da-68c735c3489c",
"detailsType": 2,
"message": "Max retries reached (0)",
"detailCreatedDate": "2018-11-01T21:37:34.892Z",
"privileges": null
},
{
"id": "009c6efc-ca33-44d3-b8f6-86396b441e6c",
"detailsType": 2,
"message": "Changing task state to Triggered",
"detailCreatedDate": "2018-11-01T21:37:33.770Z",
"privileges": null
},
{
"id": "352f0b8e-e956-4b82-8b8b-826144cdad48",
"detailsType": 2,
"message": "Trying to start task. Sending task to slave scheduler QLIKSENSESERVER",
"detailCreatedDate": "2018-11-01T21:37:33.998Z",
"privileges": null
},
{
"id": "16e3ec30-5ea1-4bd2-afe5-24b66ce9414f",
"detailsType": 2,
"message": "Reference to scriptlog added",
"detailCreatedDate": "2018-11-01T21:37:34.779Z",
"privileges": null
}
],
"privileges": null,
"schemaPath": "ExecutionResult"
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.