Skip to content

Active monitors

Unlike heartbeat, where your service “calls” Notifly, an active monitor works the other way: a Notifly serverless function itself polls the specified resource every N seconds. If a configured number of attempts in a row fail, an alert is sent; when the connection is restored, a recovery is sent.

There are 26 supported check types — from a simple HTTP GET to lightweight protocol handshakes for mail, databases, queues and network services, DNS resolution and TLS certificate expiry checks.

Basic checks:

kindWhat it checksTarget format
httpGET <url>, expects 2xx (or expectedStatus)https://example.com/health
tcpTCP handshake — port is openhost:port
tlsTCP+TLS handshake; expectedStatus = minimum certificate validity buffer (days)host:port
dnsResolve a name using the system or specified resolverexample.com or example.com@8.8.8.8:53

Protocol handshakes (target is always host:port):

kindWhat it checks
smtpTCP, read 220 banner, send EHLO/QUIT
imapTCP, wait for * OK ..., send a LOGOUT
pop3TCP, wait for +OK ..., send QUIT
sshTCP, read SSH-... banner
ftpTCP, wait for 220 banner, send QUIT
redisTCP, send PING, expect +PONG
postgresTCP, send StartupMessage, expect R/E/N
mysqlTCP, read handshake packet (protocol_version=10)
mongodbTCP, send hello (OP_MSG), expect a response
memcachedTCP memcached check
clickhouseTCP ClickHouse check
cassandraTCP Cassandra check
zookeeperTCP ZooKeeper check
mqttTCP MQTT broker check
kafkaTCP Kafka check
amqpTCP AMQP / RabbitMQ check
natsTCP, wait for INFO ... banner
ldapTCP, send SearchRequest, expect a response
rdpTCP, send X.224 Connection Request, expect a response
sipUDP, OPTIONS (default port :5060)
ntpUDP, NTP request (default port :123)
snmpUDP, SNMPv1 GetRequest (default port :161)

All TLS variants are performed over regular TCP (without StartTLS), so for encrypted ports specify the already-encrypted port (smtp:465, imap:993, pop3:995, redis:6380, etc.). To check plain TCP connectivity itself — use kind: "tcp".

every minute: timer-trigger → notifly-monitor
└─▶ SELECT WHERE next_check_at <= now AND status != "paused"
└─▶ HTTP GET / TCP Dial with timeoutSec
├─ success → status=up, fail_count=0
│ if it was "down" and recoveryMessage exists → recovery
└─ failure → fail_count++; if ≥ consecutiveFails and not "down":
send alert, status=down
  • Storagemonitors table in YDB Serverless, indexed by next_check_at.
  • Check — a separate Cloud Function notifly-monitor, triggered by a Yandex Cloud timer (cron * * * * ? * — once per minute).
  • Notification — a normal Notifly message is sent via the channel chosen when creating the monitor and reaches all your clients (web, Android, desktop) like any other push notification.

Since Notifly initiates the communication, there are two explicit events:

EventWhen sentText
Loss of connectivity (alert)After consecutiveFails consecutive failures, only on the first transition to down. The message includes the technical error (e.g. dial tcp: connect: connection refused)alertMessage
Recovery (recovery)On the first successful check after being down, only if recoveryMessage is setrecoveryMessage

There will be no repeated alert spam: while the monitor is down, no new messages are sent, checks continue at the usual interval and simply record the status.

  1. Open app.notifly.ruMonitors.
  2. Click “Create monitor”, fill in:
    • Name — for display, e.g. “Prod site” or “Postgres replica”.
    • Channel — which channel to send the notification through.
    • Check type — one of the 26 supported kind values (see tables above).
    • Target — format depends on the type: URL, host:port or DNS name.
    • Period (sec) — between checks (minimum 30, maximum 86400).
    • Timeout (sec) — how long to wait for a response in one attempt (default 10, maximum 30).
    • Consecutive fails — how many consecutive failed checks before an alert (default 1; typically 2–3 to avoid reacting to single network jitters).
    • Expected HTTP status (only http) — 0 means “any 2xx”, otherwise a specific code (e.g. 200).
    • Certificate buffer, days (only tls) — 0 = do not check; 30 = alert 30 days before expiry.
    • Alert / recovery message — text that will appear in the push.
Окно терминала
# HTTP check
curl -X POST "$NOTIFLY_URL/monitor" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{
"appid": 12345,
"name": "Прод-сайт",
"kind": "http",
"target": "https://example.com/health",
"intervalSec": 60,
"timeoutSec": 10,
"expectedStatus": 0,
"consecutiveFails": 2,
"alertMessage": "Сайт недоступен!",
"alertPriority": 9,
"recoveryMessage": "Сайт снова отвечает."
}'
# TCP check
curl -X POST "$NOTIFLY_URL/monitor" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{
"appid": 12345,
"name": "Postgres-реплика",
"kind": "tcp",
"target": "db-replica.internal:5432",
"intervalSec": 60,
"timeoutSec": 5,
"consecutiveFails": 3,
"alertMessage": "Реплика не принимает соединения.",
"recoveryMessage": "Реплика снова доступна."
}'
# TLS — alert 30 days before certificate expiry
curl -X POST "$NOTIFLY_URL/monitor" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{
"appid": 12345,
"name": "SSL prod",
"kind": "tls",
"target": "example.com:443",
"intervalSec": 3600,
"timeoutSec": 10,
"expectedStatus": 30,
"alertMessage": "Сертификат example.com истекает менее чем через 30 дней!"
}'
# DNS — resolve check via the specified server
curl -X POST "$NOTIFLY_URL/monitor" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{
"appid": 12345,
"name": "DNS prod-зоны",
"kind": "dns",
"target": "example.com@8.8.8.8:53",
"intervalSec": 300,
"timeoutSec": 5,
"alertMessage": "DNS-зона example.com не резолвится через 8.8.8.8"
}'

Typical kind + target combinations for common tasks:

{ "kind": "smtp", "target": "mx.example.com:25" } // SMTP-MX responds
{ "kind": "imap", "target": "imap.example.com:143" } // IMAP is alive (plain)
{ "kind": "pop3", "target": "pop3.example.com:110" } // POP3 is alive
{ "kind": "ssh", "target": "jump.example.com:22" } // SSH banner
{ "kind": "redis", "target": "redis.example.com:6379"} // Redis responds to PING
{ "kind": "postgres", "target": "pg.example.com:5432" } // PostgreSQL accepts connections
{ "kind": "mysql", "target": "db.example.com:3306" } // MySQL sends handshake
{ "kind": "tls", "target": "smtps.example.com:465", "expectedStatus": 14 } // SSL certificate is valid and won't expire within the next 14 days

If you have a Notifly MCP server set up (see MCP), just ask:

Create a monitor for https://api.example.com/health, check every 30 seconds, alert after 3 consecutive failures with text “API is down”, recovery “API is working again”.

Available MCP tools: list_monitors, create_monitor, update_monitor, delete_monitor, pause_monitor, resume_monitor.

MethodPathDescription
GET/monitorList user’s monitors
POST/monitorCreate
PUT/monitor/:idUpdate settings (cannot change appid)
DELETE/monitor/:idDelete
POST/monitor/:id/pausePause (checks are not performed)
POST/monitor/:id/resumeResume
POST/monitor/testOne-off check (dry-run) without creating a monitor — returns ok, durationMs, details, error
GET/monitor-history/:kind/:idCheck history: aggregated buckets (uptime %, average response time); params bucket (1m/1h/1d), from, to
GET/monitor-history/:kind/:id/logLatest check log entries; param limit (default 50, max 200)

All endpoints require a client token (Basic Auth with username/password also works). An MCP token needs write access for mutating operations (POST/PUT/DELETE, and pause/resume); for reading (GET lists, history) and for POST /monitor/test read is sufficient.

The POST /monitor/test endpoint accepts { "kind", "target", "timeoutSec", "expectedStatus" } and performs a single check right away, saving nothing — useful to verify target reachability before creating a monitor:

Окно терминала
curl -X POST "$NOTIFLY_URL/monitor/test" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{ "kind": "tcp", "target": "db.example.com:5432", "timeoutSec": 5 }'
# → {"ok":true,"durationMs":42,"details":"connected"}

You can view history for any monitor type by substituting the kind (for example http, tcp, dns) and the monitor id.

The /monitor described above are “lightweight” protocol checks (HTTP GET, TCP handshake, DNS, TLS expiry). For more complex scenarios Notifly offers specialized monitors with their own settings, timeout limits and separate REST APIs:

  • HTTP monitors — full HTTP requests with method, headers, body, status/content/time checks (timeout up to 30 s).
  • Content monitors — watch for page content changes (hash, keyword, regex), timeout up to 60 s.
  • Port monitors — check a host’s set of ports (timeout up to 10 s).
  • Port scanning — detect opened/closed ports and notify on changes.
  • Workflow monitors — chains of HTTP steps with value extraction and assertions (timeout up to 60 s).
  • Browser-workflow — scenarios in a real browser (clicks, input, page checks), timeout up to 120 s.

Related monitoring features:

  • Metrics — ingest numeric metrics and alert on thresholds.
  • Domain verification — confirm ownership of a host.
  • Heartbeat — the reverse scenario: the service periodically “pings” Notifly, and an alert is sent on missed pings.

See the same argumentation for heartbeat: an indexed point query by next_check_at is cheaper and faster than enumerating S3 objects.

  • Minimum period: 30 seconds (to avoid overloading YDB).
  • Maximum period: 24 hours (for very rare checks it’s better to use heartbeat).
  • A single notifly-monitor invocation processes up to 150 overdue monitors (the cron runs once per minute, checks run in parallel, by default up to 100 concurrently; if there are more overdue items the function self-invokes).
  • Requests originate from Yandex Cloud, so the target resource must be reachable from the public internet (or from a private YC network if the function is in the appropriate VPC).
  • All protocol-specific checks (smtp/imap/pop3/…) are performed without StartTLS — for an encrypted variant use the already-encrypted port (:465, :993, :995, :6380) with kind: "tls" or kind: "tcp".