Monitoring web services availability with Tines
I’ve been using UptimeRobot for a while now but they have recently removed features ‘we’ paid for and are asking extra for it 🤦🏻♀️ UPDATE: seems I was not the only one complaining haha, the post was updated with: ‘We’ve decided not to restrict legacy users.’
Anyhow, I’ve been playing and working with Tines recently, its a visual programming automation platform and this made me wonder if I could replace UptimeRobot with Tines
I’ve written a small Tines story to exactly achieve this.
This can be used to monitor internal services (if you have an Enterprise license with a self-hosted node) or monitor your company’s website, services, you name it.
I’ve opted to use PushOver, but you can easily switch out the notification block with your Slack block or Twilio block or whatever you want
The flow goes as follows:
My story has been published in the Tines story library over here 🥳 in case you want to try it out or take a closer look at it
My approach was to just give it an array of services I want to check, what method and what the expected reply should be (status codes) if the reply is different than the one I was expecting it will ping me on PushOver to alert me something is up
the config is as follows
[ { "url": "https://cln.io", "method": "get", "timeout": 5, "expected_status_code": 200 }, { "url": "https://tines.com", "method": "get", "timeout": 5, "expected_status_code": 200 } ]
the end result (you can customize everything about the alert! have fun)
The neat thing is that if you schedule your story to check every 10 minutes or so you can do it on their free plan 🙃 so you basically get free monitoring with push notifications
If you want the entire story as a copy paste for easier import, here you go:
{ "standardLibVersion": "14", "actionRuntimeVersion": "3", "agents": [ { "disabled": false, "name": "URL's to monitor", "description": "An array containing the URL's to monitor", "options": "{\"mode\":\"message_only\",\"loop\":false,\"payload\":[{\"url\":\"https://google.com\",\"method\":\"get\",\"timeout\":5,\"expected_status_code\":200},{\"url\":\"https://tines.com\",\"method\":\"get\",\"timeout\":5,\"expected_status_code\":200},{\"url\":\"https://httpbin.org/post\",\"method\":\"post\",\"timeout\":3,\"expected_status_code\":200},{\"url\":\"https://httpbin.org/post\",\"method\":\"get\",\"timeout\":3,\"expected_status_code\":200},{\"url\":\"https://this-is-a-non-existing-domain.com\",\"method\":\"get\",\"timeout\":3,\"expected_status_code\":200},{\"url\":\"https://github.com\",\"method\":\"get\",\"timeout\":3,\"expected_status_code\":200}]}", "position": { "x": 705, "y": 180 }, "schedule": [ { "cron": "*/10 * * * *", "timezone": "Etc/UTC" } ], "type": "eventTransformation", "timeSavedUnit": "minutes", "timeSavedValue": 0, "monitorAllEvents": false, "monitorFailures": false, "monitorNoEventsEmitted": null, "form": null }, { "disabled": false, "name": "Explode URL Array", "description": "We explode the array into individual bits and continue the story below 1 by 1", "options": "{\"mode\":\"explode\",\"path\":\"=url_s_to_monitor\",\"to\":\"service\"}", "position": { "x": 705, "y": 270 }, "type": "eventTransformation", "timeSavedUnit": "minutes", "timeSavedValue": 0, "monitorAllEvents": false, "monitorFailures": false, "monitorNoEventsEmitted": null, "form": null }, { "disabled": false, "name": "Request the URL", "description": "", "options": "{\"url\":\"<<explode_url_array.service.url>>\",\"content_type\":\"application_json\",\"method\":\"<<explode_url_array.service.method>>\",\"timeout\":\"<<NUMBER(explode_url_array.service.timeout)>>\",\"log_error_on_status\":[]}", "position": { "x": 705, "y": 360 }, "type": "httpRequest", "timeSavedUnit": "minutes", "timeSavedValue": 0, "monitorAllEvents": false, "monitorFailures": false, "monitorNoEventsEmitted": null, "form": null }, { "disabled": false, "name": "Check for an expected reply", "description": "", "options": "{\"rules\":[{\"type\":\"field!=value\",\"value\":\"<<explode_url_array.service.expected_status_code>>\",\"path\":\"<<request_the_url.status>>\"}]}", "position": { "x": 705, "y": 435 }, "type": "trigger", "timeSavedUnit": "minutes", "timeSavedValue": 0, "monitorAllEvents": false, "monitorFailures": false, "monitorNoEventsEmitted": null, "form": null }, { "disabled": false, "name": "Send notification to Pushover", "description": "", "options": "{\"url\":\"https://api.pushover.net/1/messages.json\",\"content_type\":\"json\",\"method\":\"post\",\"payload\":{\"token\":\"<<CREDENTIAL.pushover_app_token>>\",\"user\":\"<<CREDENTIAL.pushover_user_key>>\",\"message\":\"=prepare_notification_message.message\"},\"headers\":{}}", "position": { "x": 705, "y": 585 }, "type": "httpRequest", "timeSavedUnit": "minutes", "timeSavedValue": 0, "monitorAllEvents": false, "monitorFailures": false, "monitorNoEventsEmitted": null, "form": null }, { "disabled": false, "name": "prepare notification message", "description": "", "options": "{\"mode\":\"message_only\",\"loop\":false,\"payload\":{\"message\":\"Tines⚠️ a service you monitor (<<explode_url_array.service.url>>) did not reply as expected\\n<%if request_the_url.status = 0%> <<request_the_url.connection_error>><%else%>) reply was [<<request_the_url.status>>] but we expected [<<explode_url_array.service.expected_status_code>>]<%endif%>\"}}", "position": { "x": 705, "y": 510 }, "type": "eventTransformation", "timeSavedUnit": "minutes", "timeSavedValue": 0, "monitorAllEvents": false, "monitorFailures": false, "monitorNoEventsEmitted": null, "form": null } ], "links": [ { "sourceIdentifier": 0, "receiverIdentifier": 1 }, { "sourceIdentifier": 1, "receiverIdentifier": 2 }, { "sourceIdentifier": 2, "receiverIdentifier": 3 }, { "sourceIdentifier": 3, "receiverIdentifier": 5 }, { "sourceIdentifier": 5, "receiverIdentifier": 4 } ], "diagramNotes": [ { "position": { "x": 960, "y": 285 }, "content": "# Overview\n\nMonitor a list of web services for their availability. Configure the maximum time a service should respond by and the normal operating status codes that should be turned.\n\nIf the given service matches a failure condition, send a push notification to [Pushover](https://pushover.net/).\n", "width": null }, { "position": { "x": 375, "y": 435 }, "content": "# Requirements:\n\n- [ ] A Credential `pushover_app_token` as a [Pushover app token](https://pushover.net/apps/build) \n- [ ] A Credential `pushover_user_key` as a Pushover user key. Viewable when logged into your [dashboard](https://pushover.net/dashboard).", "width": 264 }, { "position": { "x": 900, "y": 180 }, "content": "⬅️ The monitoring schedule is located in here (default is every ten minutes).", "width": null }, { "position": { "x": 345, "y": 210 }, "content": "https://image-uploads.tines.com/upload-pushover.png", "width": 332 } ] }