Below is a JSON export of the Postman collection I am using to mock an AE executions callback listener.
{
"info": {
"name": "AE executions callback",
"description": "Listen and respond to AE execution callbacks.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Register an AE executions callback",
"request": {
"auth": {
"type": "noauth"
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
},
{
"key": "x-mock-response-code",
"value": "200",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"runid\": \"219020002\",\r\n \"object_type\": \"SCRI\",\r\n \"execution_status\": \"1900\",\r\n \"execution_status_text\": \"ENDED_OK - ended normally\",\r\n \"ae_system\": \"AE_EXP\",\r\n \"client_number\": \"0001\",\r\n \"client_description\": \"\",\r\n \"user_department\": \"MYUSER/TEST\",\r\n \"archive_key1\": \"Test 1\",\r\n \"last_error_message\": \"\",\r\n \"last_error_code\": \"00000000\",\r\n \"last_error_insert\": \"\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{MOCK_SERVER}}/ae_executions_callback",
"host": [
"{{MOCK_SERVER}}"
],
"path": [
"ae_executions_callback"
]
},
"description": "Register an _executions_ API callback from the Automation Engine."
},
"response": [
{
"name": "Callback registered successfully",
"originalRequest": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"value": "application/json",
"type": "text"
},
{
"key": "Accept",
"value": "application/json"
},
{
"key": "x-mock-response-code",
"value": "200",
"type": "text"
},
{
"key": "x-api-key",
"value": "{{API_KEY}}",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"runid\": \"219020002\",\r\n \"object_type\": \"SCRI\",\r\n \"execution_status\": \"1900\",\r\n \"execution_status_text\": \"ENDED_OK - ended normally\",\r\n \"ae_system\": \"AE_EXP\",\r\n \"client_number\": \"0001\",\r\n \"client_description\": \"\",\r\n \"user_department\": \"MYUSER/TEST\",\r\n \"archive_key1\": \"Test 1\",\r\n \"last_error_message\": \"\",\r\n \"last_error_code\": \"00000000\",\r\n \"last_error_insert\": \"\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{MOCK_SERVER}}/ae_executions_callback",
"host": [
"{{MOCK_SERVER}}"
],
"path": [
"ae_executions_callback"
]
}
},
"status": "OK",
"code": 200,
"_postman_previewlanguage": "json",
"header": [
{
"key": "Date",
"value": "Thu, 07 Mar 2024 10:30:09 GMT"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Content-Length",
"value": "26"
}
],
"cookie": [],
"body": "{\r\n \"message\": \"Callback registered successfully.\",\r\n \"callback_payload\": {{$body}}\r\n}"
},
{
"name": "Callback not registered successfully",
"originalRequest": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"value": "application/json",
"type": "text"
},
{
"key": "Accept",
"value": "application/json"
},
{
"key": "x-mock-response-code",
"value": "404",
"type": "text"
},
{
"key": "x-api-key",
"value": "{{API_KEY}}",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"runid\": \"219020002\",\r\n \"object_type\": \"SCRI\",\r\n \"execution_status\": \"1900\",\r\n \"execution_status_text\": \"ENDED_OK - ended normally\",\r\n \"ae_system\": \"AE_EXP\",\r\n \"client_number\": \"0001\",\r\n \"client_description\": \"\",\r\n \"user_department\": \"MYUSER/TEST\",\r\n \"archive_key1\": \"Test 1\",\r\n \"last_error_message\": \"\",\r\n \"last_error_code\": \"00000000\",\r\n \"last_error_insert\": \"\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{MOCK_SERVER}}/ae_executions_callback",
"host": [
"{{MOCK_SERVER}}"
],
"path": [
"ae_executions_callback"
]
}
},
"status": "Not found",
"code": 404,
"_postman_previewlanguage": "json",
"header": [
{
"key": "Date",
"value": "Thu, 07 Mar 2024 10:30:09 GMT"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Content-Length",
"value": "26"
}
],
"cookie": [],
"body": "{\r\n \"message\": \"Run ID could not be associated with a task executed by this application.\",\r\n \"callback_payload\": {{$body}}\r\n}"
}
]
}
],
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "API_KEY",
"value": "<replcae with your Postman API key.>",
"type": "string"
},
{
"key": "MOCK_SERVER",
"value": "<replcae with your Postman mock server URL.>",
"type": "string"
}
]
}
In a separate collection with the AE REST APIs, I created a new example for the executions endpoint. I modified the JSON body to include the callback:
{
"object_name": "EBM.TEST.SCRI",
"callback": {
"type": "http",
"recurring_mode": "once",
"http": {
"url": "{{MOCK_SERVER}}/ae_executions_callback",
"headers": {
"x-mock-response-code": "200",
"x-api-key": "{{API_KEY}}"
}
}
}
}
The x-api-key
header is used to grant authorization to a private mock server.
The x-mock-response-code
header serves two purposes:
- When the mock server receives a request, Postman uses this header to identify which example to match in the collection.
- The mock server returns the specified HTTP response code to the JWP executing the callback.
The mock server is configured as follows:
The AE will mark the callback task ENDED_OK upon receiving any successful (2XX) HTTP response code from the callback listener.
The body and actual response code of the callback response are evidently discarded. If you want to somehow communicate back from the callback listener to the AE that the callback was not successful, you would have to configure it to return a client error (4XX) response code such as 404. This causes the AE to mark the callback task ENDED_NOT_OK. You might want to do this if the AE callback for some reason includes a Run ID that cannot be associated with a task executed by the external application. (And it might be possible to perform some additional checking of CBCK tasks via AE scripting.) To test this, I created a second executions example wherein x-mock-response-code
and the expected response code are set to 404.
We execute thousands of tasks per day in the AE from external applications. Today, these applications check the status of submitted tasks by periodically polling the AE DB directly. This allows the external applications to retrieve the current status of many hundreds of tasks in a single transaction. (It also allows us to work around a bug in the TaskFilter class that prevents listing tasks with aliases by their original object names.) With our use cases, switching from polling to callbacks might result in more overhead, not less. Still, it is an interesting new capability.