Kronus
Kronus is a tool for asessing users "aliveness" via liveliness probes and
actioning on it based on the results of the probe.
Its key features are:
-
Sending Liveliness Probes: The kronus server sends out probes to users on the
server and based on their response, determines their "aliveness".
-
Contact Emergency Contact: When the service doesn't get a response back
from a user or gets a bad
response, the user's emergency contact is alerted.
-
Flexible API: Allow developers to add extra functionality based on a user's
"aliveness". A user's probes
can be queried periodically from kronus server
to see the status
of the last probe. And based on that, do whatever the
developer wants.
CLI Usage
Usage:
kronus [command]
Available Commands:
completion generate the autocompletion script for the specified shell
help Help about any command
server Start a kronus server
Flags:
--dev run in development mode
-h, --help help for kronus
-t, --toggle Help message for toggle
-v, --version version for kronus
Use "kronus [command] --help" for more information about a command.
SMS Usage
In addition to responding to probe via sms, few commands are
supported for numbers on the server
Usage:
[command]
Available Commands:
usage List available commands
probe Ask kronus to check on you in a couple minutes
ping Health check for the server
Use "[command] --help" for more information about a command.
Dependencies
Install
go get -u github.com/Daskott/kronus
Server Config
The server requires a valid config.yml
configuration file as shown below:
kronus:
# A valid RSA private key for creating/validating kronus server jwts
# You can can use this https://mkjwk.org/ to generate one
privateKeyPem:
# If deployed to a production env, the public url of the server.
# It's required, as this will be used for the twilio webhook
publicUrl: "https://my-app.com"
cron:
# Timezone to use for scheduling probes
timeZone: "America/Toronto"
listener:
port: 3900
sqlite:
passPhrase: passphrase
google:
storage:
bucket: "gstorage-bucket-name"
# The folder/path to store backup files
prefix: "kronus"
# How often you want your sqlite db to be backed up to google storage in cron format
sqliteBackupSchedule: "0 * * * *"
enableSqliteBackupAndSync: true
# The path to google service account credentials. You may not need to set this, if the
# kronus server is deployed to a google compute engine instance - the default credentials may be used instead.
applicationCredentials: "/path/to/google/credentials"
twilio:
accountSid: AHKX00SXXXXXXXXXXXXXXXXXXX
authToken: BHKX00SXXXXXXXXXXXXXXXXXXX
messagingServiceSid: CHKX00SXXXXXXXXXXXXXXXXXXX
Start server in dev mode
kronus server --dev
Start server with config
kronus server --config=config.yml
Setup steps
API and Usage
Create user
-
The first user created is assigned the admin
role and every other user has to be created by the admin
.
A default probe_settings
is created for the user account, and active
is set to false
.
Method |
Path |
POST |
/webhook/sms |
Sample Request:
curl --request POST 'localhost:3900/v1/users' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data-raw '{
"first_name": "tony",
"last_name": "stark",
"email": "stark@avengers.com",
"password": "very-secure",
"phone_number": "+12345678900"
}'
Sample Response:
{
"success": true,
"data": {
"id": 1,
"created_at": "2022-01-10T19:54:53.708959-07:00",
"updated_at": "2022-01-10T19:54:53.708959-07:00",
"first_name": "tony",
"last_name": "stark",
"phone_number": "+12345678900",
"email": "stark@avengers.com",
"role_id": 1,
"probe_settings": {
"id": 1,
"created_at": "2022-01-10T19:54:53.709185-07:00",
"updated_at": "2022-01-10T19:54:53.709185-07:00",
"user_id": 1,
"active": false,
"cron_expression": "0 18 * * 3",
"max_retries": 3,
"wait_time_in_minutes": 60
}
}
}
Get access token
-
Get access token
which will be used to query protected resources
Sample Request:
curl --request POST 'localhost:3900/login' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "stark@avengers.com",
"password": "very-secure"
}'
Sample Response:
{
"success": true,
"data": {
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...."
}
}
-
For protected routes, the token
from the /login needs to be added to the Authorization
header as Bearer <token>
Method |
Path |
POST |
/users/{uid}/contacts |
Sample Request:
curl --location --request POST 'localhost:3900/v1/users/1/contacts' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data-raw '{
"first_name": "strongest",
"last_name": "avenger",
"phone_number": "+12345678900",
"email": "hulk@avengers.com",
"is_emergency_contact": true
}'
Sample Response:
{
"success": true,
"data": {
"id": 1,
"created_at": "2022-01-10T20:25:40.878785-07:00",
"updated_at": "2022-01-10T20:25:40.878785-07:00",
"first_name": "strongest",
"last_name": "avenger",
"phone_number": "+12345678900",
"email": "hulk@avengers.com",
"user_id": 1,
"is_emergency_contact": true
}
}
Update probe settings
-
Set how often you'd like to get a probe message with a cron_expression
and use active
to
enable/disable probe.
Method |
Path |
PUT |
/users/{uid}/probe_settings |
Sample Request:
curl --request PUT 'localhost:3900/v1/users/1/probe_settings' \
--header 'Authorization: Bearer <token>' \
--data-raw '{
"cron_expression": "0 18 * * */1",
"active": true
}'
Sample Response:
{
"success": true,
"data": {
"id": 1,
"created_at": "2022-01-10T19:54:53.709185-07:00",
"updated_at": "2022-01-10T20:33:16.828639-07:00",
"user_id": 1,
"active": true,
"cron_expression": "0 18 * * */1",
"max_retries": 3,
"wait_time_in_minutes": 60
}
}
Retrieve user probes
-
Get probes for a user, with the probe's status
Method |
Path |
GET |
/users/{uid}/probes |
Sample Request:
curl --request GET 'localhost:3900/v1/users/1/probes' \
--header 'Authorization: Bearer <token>'
Sample Response:
{
"success": true,
"data": [
{
"id": 1,
"created_at": "2022-01-12T14:43:02.79022-07:00",
"updated_at": "2022-01-12T19:15:49.854305-07:00",
"last_response": "",
"retry_count": 3,
"emergency_probe": {
"id": 1,
"created_at": "2022-01-12T19:15:49.854767-07:00",
"updated_at": "2022-01-12T19:15:49.854767-07:00",
"contact_id": 1,
"probe_id": 1
},
"user_id": 1,
"probe_status_id": 4,
"status": {
"id": 4,
"created_at": "2021-01-10T16:57:18.809242-07:00",
"updated_at": "2021-01-10T16:57:18.809242-07:00",
"name": "unavailable"
}
}
],
"paging": {
"total": 1,
"page": 1,
"pages": 1
}
}
Other routes
Method |
Route |
Note |
POST |
/webhook/sms |
For twilio message webhook |
GET |
/jwks |
For validating kronus server jwts |
GET |
/health |
To check service health |
GET |
/v1/users/{uid} |
Can only GET your own record, except if you're admin |
PUT |
/v1/users/{uid} |
Can only UPDATE own record |
DELETE |
/v1/users/{uid} |
Can only DELETE your own record, except if you're admin |
GET |
/v1/users/{uid}/contacts |
Fetch all contacts for a given user where uid is the user id. Supports optional page filter for pagination |
PUT |
/v1/users/{uid}/contacts/{id} |
Update contact for a user |
DELETE |
/v1/users/{uid}/contacts/{id} |
Delete user contact |
GET |
/v1/users |
Fetch all users. Supports optional page filter for pagination [admin-only] |
GET |
/v1/jobs/stats |
Get job stats i.e. no of jobs in each group e.g. enqueued , successful , in-progress or dead - [admin-only] |
GET |
/v1/jobs?status= |
Fetch jobs with optional filter - status which could be enqueued , successful , in-progress or dead . Also supports pagination - [admin-only] |
GET |
/v1/probes/stats |
Get probe stats i.e. no of probes in each group e.g. pending , good , bad cancelled , or unavailable - [admin-only] |
GET |
/v1/probes?status= |
Fetch probes with optional filter - status which could be pending , good , bad cancelled , or unavailable . Also supports pagination - [admin-only] |
Development
Publishing package
-
Update Version
in version.go
-
Commit changes:
git commit -m "kronus: changes for v0.x.x"
-
Run:
make release VERSION=0.x.x
For more info see detailed steps https://golang.org/doc/modules/publishing
Design Concepts
Probes
- Probes are events used to identify when a user has been contacted by the service to check on their aliveness.
- A probe can be in 5 possible states:
pending
- The server has sent out a probe message to the user & is awaiting a response e.g. "Are you okay Stark?"
good
- The server has gotten a valid response for good i.e Yes
, Yeah
, Yh
or Y
bad
- The server has gotten a valid response for bad i.e No
, Nope
, Nah
or N
cancelled
- The probe was cancelled by the user via the rest API
unavailable
- The server did not receive any response after multiple retries i.e "You good ??"
- In both a
bad
or unavailable
state the server sends out a message to the
user's emergency contact and then disables the probe.
FAQ