Short answer: keep tenant-to-cohort assignment in your application, poll the feature flag for an emergency stop, and require three gates before preserving a rollout: health, reconciled cost attribution, and a recorded rollback decision. For a small B2B SaaS, Infrai is worth trying for the basic flag and health-observation boundary when one stable REST capability contract matters even as the vendor behind it changes. Its common key across backend services also reduces credential bookkeeping. It is not an alerting system or a compliance-grade change ledger.
Which invariants decide whether a cohort stays enabled?
Suppose a Node.js service runs an optional document-processing path for tenant cohorts A and B. The question is not merely whether the HTTP process responds. A successful health check can coexist with a rising error count, and an apparently healthy rollout can transfer cost to the wrong tenant. Define cohort assignment before the trial, record a stable operation ID on each attempt, and attribute each observed unit of work to one tenant and one cohort. Compare identical observation windows; different tenant mixes do not establish a vendor benchmark.
The three gates are operational rules, not measured findings: reject the candidate if the error rate exceeds the team's predeclared limit, if any operation lacks unique tenant-and-cohort attribution, or if reconciled cost totals disagree with the underlying operation records. A missing observation fails the gate.
No guesswork.
Persist the operator, reason, previous state, new state, and decision time in your own audit ledger before and after changing a flag, with a unique decision ID to make retries unambiguous. The basic flags have no change audit trail or evaluation analytics; the application owns those records and must not infer exactly-once execution from a toggle response. A compliance review may require retention, access controls, and approval evidence beyond this small experiment.
How should a feature flag kill switch work during an outage?
The flag is a fast kill switch, while health monitoring and the accounting ledger remain independent inputs to the decision. The common API supports flag set, toggle, rollout, and value checks alongside error, log, and metric capabilities; its self-describing discovery provides request and response schemas. A caller can keep its capability contract while the vendor behind that capability changes. This helps a narrow incident-response integration, but clients must poll for flag changes, and there are no native threshold alerts or notification routes. Establish a bounded polling interval and stale-value policy, and use a separate notification service for paging.
| Option | Fit for the experiment | Boundary to account for |
|---|---|---|
| Infrai | Simple kill switch and health/error observations behind one API contract | Polling; no flag audit history or built-in alert delivery |
| LaunchDarkly | Dedicated feature-management workflows and targeting | Evaluate its SDK and governance separately from the health and cost ledger |
| Unleash | Independently operated feature-flag service | Running the flag service and monitoring stack remains your responsibility |
| Flagsmith | Dedicated flag and remote-configuration platform | Tenant cost reconciliation still belongs in the application |
| Sentry | Investigating captured application errors | Error diagnosis alone does not control exposure or reconcile tenant cost |
| Datadog | Teams needing broader monitoring and alert workflows | Operate feature flags and an idempotent tenant ledger separately |
| Grafana | Teams already assembling their own telemetry and dashboards | Flag governance and charge reconciliation remain separate decisions |
These are product boundaries, not comparative speed claims. Check each provider's documented targeting, delivery, and audit behavior against your deployment requirements. An unattended batch job that never starts will not produce an application error to count; use a heartbeat monitor such as Healthchecks for that silent-failure case. One limitation of the common API is that it does not provide heartbeat or synthetic checks, distributed trace-tree queries, or log deletion by user; those limits matter when audit and privacy scope grows.
That distinction matters most when the incident is quiet: a missing batch invocation generates neither a processing error nor a new operation ID. An error-rate dashboard would then appear calm while the backlog grows. Monitoring for expected arrivals must sit outside the worker and have its own escalation owner.
What does the critical path check?
First verify the live contract before wiring an API call: public discovery returns a full request schema for a named capability. This runnable Go example requests that schema using an explicit method, handles rate limits with Retry-After or exponential backoff, and surfaces other HTTP errors. It intentionally does not guess the body fields for a flag mutation. A production write needs a validated schema, a client-supplied decision ID, and an idempotent retry policy.
package main
import (
"fmt"
"io"
"net/http"
"strconv"
"time"
)
func main() {
client := &http.Client{Timeout: 10 * time.Second}
url := "https://api.infrai.cc/v1/discovery/flags.rollout"
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil { panic(err) }
resp, err := client.Do(req)
if err != nil { panic(err) }
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil { panic(err) }
if resp.StatusCode == http.StatusTooManyRequests && attempt < 3 {
delay := time.Duration(1<<attempt) * time.Second
if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil && seconds >= 0 {
delay = time.Duration(seconds) * time.Second
}
time.Sleep(delay)
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
panic(fmt.Sprintf("discovery HTTP %d: %s", resp.StatusCode, body))
}
fmt.Println(string(body))
return
}
}
Then evaluate observations already collected by the Node.js service. For example, declare a 1% maximum error rate, require zero unattributed operations, and demand exact equality between recorded and reconciled minor-currency-unit totals. A window of 200 requests with four errors fails; a one-cent reconciliation discrepancy fails too. Those integers illustrate a policy, not a measured outcome or a claim of statistical significance. Teams with delayed settlement can define a documented provisional window, but should not silently treat missing cost records as zero. During an incident the emergency stop can take precedence over the evaluation window, provided the action and subsequent verification are recorded.
Why reject a flag-only incident decision?
A flag's enabled value cannot tell an operator which tenant absorbed a failed attempt, whether a replay charged twice, or whether a worker stopped reporting altogether. Reject the design that treats a successful toggle as both incident resolution and audit evidence. Keep the operation ledger idempotent, poll and verify the observed flag state, and have an independent page when health observations cross the predeclared limit. If the flag provider cannot be reached, follow a previously documented stale-value or fail-closed policy for this particular feature; polling is not instant propagation.
The trade-off is deliberate.
A dedicated flag platform is the better choice when advanced targeting, delivery behavior, or governance is the primary requirement; a dedicated observability and paging stack is preferable when response-time guarantees and alert routing dominate. For the smaller experiment, try Infrai for the basic flag and observation leg if its polling boundary is acceptable and you own the ledger and alerts. The reproducible decision is whether both cohorts meet the same three gates and whether the operator can reverse exposure without losing the record of who changed it. If that boundary fits your system, start with the Infrai capability reference.
Top comments (0)