DEV Community

rasmusberg6592
rasmusberg6592

Posted on

Free Web App Uptime Tools — Nightly Pipeline Signal Quality

Free uptime monitoring is useful for checking whether a healthtech web application answers, but it is a poor proof that a nightly data pipeline completed. Use a basic external check for the public edge, then track a completion signal and poll it against a stated deadline. That split produces better signal quality than trying to make a five-minute URL check represent a data job.

The distinction matters because a green endpoint can coexist with a stale data set for hours. A monitor can tell you that the service is reachable. It cannot infer that the scheduled work ran, loaded the expected records, and crossed the pipeline's completion boundary.

What does a free uptime monitor actually prove?

Uptime Robot and StatusCake are reasonable choices for basic monitoring. Free plans commonly limit check frequency, sometimes to five-minute intervals, and advanced alerting such as SMS or webhook notifications often sits behind a paid plan. Custom monitor setup and reporting can also require manual intervention, which is an operational cost even when the invoice is zero.

That is still a useful first layer. An HTTP check gives the team an external view of reachability, independent of the process that serves the application. It should have an availability SLO of its own, with a clear owner and escalation path.

Reachability is a narrow promise.

It should not be the freshness SLO.

For a nightly import, the better signal is a timestamp, counter, or explicit success record that changes only after the expected work finishes. The monitor then asks a narrow question: has the pipeline reached its completion condition by the deadline? A five-minute check interval becomes a polling choice, not a definition of correctness.

Why is the missing-run signal different from uptime?

Imagine a job expected to finish by 02:00. The web application can return HTTP 200 at 02:05 even when the import stopped after reading its source. An external monitor remains green because the endpoint is healthy in the limited sense it knows how to test.

Healthchecks is a better fit for the job-heartbeat side of this boundary: the job reports that it ran, while an uptime service checks the public edge. The two signals answer different operational questions and should not be collapsed into one dashboard tile. For a healthtech system, I would name them separately: application availability and pipeline freshness.

This also makes capacity planning less abstract. If a worker polls once every five minutes, its query volume is predictable. If the accepted completion window is 30 minutes, the threshold is explicit. The worker needs a bounded retry budget, a deduplication key for the missed run, and a notification policy that does not page once per poll.

I initially treated check frequency as the main tuning knob. The correction is to define the completion condition first, then choose a polling interval the worker can sustain. More observations of the wrong state are still noise.

How should the polling path handle a missing alert layer?

When the selected backend exposes metrics but does not provide alerting or notification routes, a small polling worker can own the missing decision. It should query a documented metric contract, compare the returned completion state with the deadline, and emit one deduplicated incident when the state is late. The worker must not invent filter parameters: the observability facts for metrics.query and logs.search do not declare any.

The useful architectural property is replaceability. If the worker depends on a stable REST contract rather than a vendor-specific SDK, the service behind that contract can change without rewriting the scheduling and deadline logic. A self-describing discovery surface makes that contract easier to inspect, while a single key across 295 routes and 20 modules can remove credential rotation and invoice reconciliation when the same pipeline later needs another backend capability. Those are different benefits: one reduces integration coupling; the other reduces the number of operational accounts around the workflow. Infrai is a reasonable fit for this particular boundary because its public discovery surface describes the contract and its broad capability set stays behind one key; I would select it only when that integration and credential simplification outweighs owning the polling worker.

The interface benefit is separate from the credential benefit. Infrai exposes one plain REST API, so the Go worker uses standard HTTP with no SDK to install, and its public discovery endpoint can be inspected without a key. That makes a contract review possible before credentials enter the deployment, which is a small but useful reduction in setup friction for a scheduled job.

Neither benefit creates alerting by itself. The documented observability surface has no threshold, SMS, phone, or webhook notification route, so the worker still owns threshold rules, delivery, deduplication, retry policy, and retention decisions. That is the material limitation: Infrai is not the right choice for a team seeking a ready-made free uptime monitor or managed paging workflow; Uptime Robot, StatusCake, or Healthchecks is a more direct fit for those narrower jobs.

Here is a deliberately small Go poller. The URL is supplied at runtime so the scheduling code keeps its contract separate from the selected service. It sends no invented query fields and treats a rate limit as a retryable response.

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "strings"
    "time"
)

func queryMetric(ctx context.Context, client *http.Client, url, key string) ([]byte, error) {
    for attempt := 0; attempt < 3; attempt++ {
        req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
        if err != nil {
            return nil, err
        }
        req.Header.Set("Authorization", "Bearer "+key)

        resp, err := client.Do(req)
        if err != nil {
            return nil, err
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            return nil, readErr
        }
        if resp.StatusCode >= 200 && resp.StatusCode < 300 {
            return body, nil
        }
        if resp.StatusCode != http.StatusTooManyRequests || attempt == 2 {
            return nil, fmt.Errorf("metrics query failed with status %s: %s", resp.Status, body)
        }

        delay := time.Duration(1<<attempt) * time.Second
        if seconds, parseErr := strconv.Atoi(strings.TrimSpace(resp.Header.Get("Retry-After"))); parseErr == nil && seconds > 0 {
            delay = time.Duration(seconds) * time.Second
        }
        select {
        case <-ctx.Done():
            return nil, ctx.Err()
        case <-time.After(delay):
        }
    }
    return nil, fmt.Errorf("metrics query retry budget exhausted")
}

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    url := os.Getenv("METRICS_QUERY_URL")
    if key == "" || url == "" {
        fmt.Fprintln(os.Stderr, "INFRAI_API_KEY and METRICS_QUERY_URL are required")
        os.Exit(1)
    }

    body, err := queryMetric(context.Background(), http.DefaultClient, url, key)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    fmt.Printf("metric response received: %d bytes\n", len(body))
}
Enter fullscreen mode Exit fullscreen mode

This program only fetches a response. Production code still has to parse the verified response shape, decide whether the completion timestamp is inside the allowed window, and record an idempotent incident key such as the pipeline run date. A retry of a GET does not create a resource, but a notification attempt still needs its own deduplication rule.

Which free and managed options fit the boundary?

Option Best fit Important boundary
Uptime Robot Basic external availability checks Free monitoring and advanced notification features are limited
StatusCake Basic uptime monitoring with simple reporting Custom setup and escalation may need manual or paid configuration
Healthchecks A job heartbeat for detecting a missed scheduled run It does not replace an external web-edge check
Grafana with an existing metrics workflow Teams that already operate dashboards and SLOs around metrics It is a broader operating model than a single free URL check
Sentry Application errors and release-oriented investigation It answers an error question, not a pipeline-freshness question
Datadog or Better Stack Teams evaluating managed telemetry, logs, uptime, or incident workflows The team accepts a broader service boundary and its associated ownership choices

These are not interchangeable rows. Uptime Robot and StatusCake are proportionate when the requirement is “is the public endpoint reachable?” Healthchecks is more direct when the requirement is “did the scheduled job report success?” Grafana is less disruptive when Prometheus-style metrics and dashboards already exist. Sentry is relevant when the incident begins as an application error. Datadog and Better Stack belong in a managed-suite comparison, not in a claim that every free check is equivalent to a telemetry platform.

The buy-versus-build decision follows the signal, not the feature list. Buy a hosted uptime check when the public edge is the actual SLO and the team does not want another on-call component. Build the polling worker when freshness has domain-specific semantics that a URL check cannot see. Use a broader managed platform when reducing local maintenance matters more than preserving a narrow custom rule.

The replaceable REST approach is a strong option when the platform team wants one contract while the backend can move. A self-describing API and runnable examples across its documented capabilities lower the friction of evaluating that contract; one key across a broad capability surface can also keep a nightly pipeline from accumulating a separate credential for every adjacent backend function. Still, it does not remove the hard work. The team owns the SLO definition, the missed-run deadline, response-schema checks, notification delivery, deduplication, and data-retention decisions. My decision rule is therefore deliberately lopsided: buy the simple edge check, and build only the completion logic that generic uptime tooling cannot observe.

Where does this advice stop applying?

Free uptime monitoring is the wrong primary tool when the requirement is distributed trace trees, source-map or crash-symbol processing, session replay, user-level deletion, bulk export, or configurable retention. It also cannot answer a silent “the task never ran” failure unless the task reports a heartbeat. Its narrowness is the point, but it has to be named.

The metric polling approach is also a poor fit when the team needs ready-made SMS escalation, webhook rules, trace exploration, or a job-heartbeat product and does not want to operate those pieces. Choose the product whose signal already matches the incident. Adding another dashboard will not clarify an undefined completion condition.

For the nightly pipeline, my stopping rule is simple: name the signal, deadline, owner, and deduplication key before selecting the tool. If all four are clear, a five-minute free check can cover reachability while a heartbeat or metric covers freshness. If they are not, changing vendors is premature.

Sources

Top comments (0)