You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/deployment.md
+13-1Lines changed: 13 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -116,6 +116,19 @@ Registered functions:
116
116
-`research-run` — triggered by `research/run.requested`
117
117
-`outbox-dispatcher` — scheduled every two minutes
118
118
119
+
After syncing the functions, enable the production failure and missing-dispatcher email alerts described in [Production monitoring](observability.md#inngest-alert-activation).
120
+
121
+
## Alerting activation
122
+
123
+
Provision or refresh the Cloud Monitoring baseline after the backend service exists:
The script configures the `/health` uptime check, 5xx burst policy, runtime/probe log alert, and email notification channel. Verify the email channel and send a test notification before treating the alarms as operational.
131
+
119
132
## Supabase migrations
120
133
121
134
The production workflow applies migrations automatically. For manual maintenance:
@@ -130,4 +143,3 @@ npx supabase db push
130
143
Every pull request and push to `main` builds the production container. CI scans the repository and image with Trivy, blocking HIGH or CRITICAL findings that have an available fix as well as serious configuration and secret findings.
131
144
132
145
CI also generates a CycloneDX container SBOM named `cortex-sbom-<commit-sha>` and retains it for 30 days. See [Testing and quality](testing-and-quality.md) for the complete release gates.
Copy file name to clipboardExpand all lines: docs/env-vars-production.md
+19-3Lines changed: 19 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ All secrets should be stored in **Google Secret Manager** and referenced via `va
8
8
9
9
| Env Var | Secret Manager | Notes |
10
10
|---|---|---|
11
-
|`PROVIDER_CONFIG_JSON`| yes | Secret JSON with provider, Redis, Langfuse, and LangSmith settings: `openai_api_key`, `tavily_api_key`, `redis_url`, `langfuse_public_key`, `langfuse_secret_key`, `langfuse_base_url`, `langsmith_api_key`, `langsmith_project`, `langsmith_endpoint`, `langsmith_redaction_mode`, `langsmith_sampling_rate`, and `langsmith_tracing`. Required when `LLM_PROVIDER=openai`. |
11
+
|`PROVIDER_CONFIG_JSON`| yes | Secret JSON with provider, Redis, Langfuse, LangSmith, and Sentry settings: `openai_api_key`, `tavily_api_key`, `redis_url`, `langfuse_public_key`, `langfuse_secret_key`, `langfuse_base_url`, `langsmith_api_key`, `langsmith_project`, `langsmith_endpoint`, `langsmith_redaction_mode`, `langsmith_sampling_rate`, `langsmith_tracing`, and `sentry_dsn`. Required when `LLM_PROVIDER=openai`. |
12
12
|`OPENROUTER_API_KEY`| yes | Required when `LLM_PROVIDER=openrouter`|
13
13
|`LLM_PROVIDER`| no |`openai` or `openrouter`|
14
14
|`OPENAI_MODEL`| no | e.g. `gpt-4o-mini`|
@@ -49,7 +49,8 @@ All secrets should be stored in **Google Secret Manager** and referenced via `va
49
49
|`LANGSMITH_*`| no | LangSmith tracing, API key, project, endpoint, redaction mode, and sampling rate are supplied through `PROVIDER_CONFIG_JSON`. |
50
50
|`LANGFUSE_ENV`| no |`prod`|
51
51
|`LANGFUSE_RELEASE`| no | Git SHA or semver, e.g. `v1.2.3`|
52
-
|`SENTRY_DSN`| yes | Error tracking; unset disables it entirely |
52
+
|`SENTRY_DSN`| no | Local/split-variable fallback. Production stores `sentry_dsn` inside `PROVIDER_CONFIG_JSON`; unset disables Sentry entirely. |
53
+
|`SENTRY_ENVIRONMENT`| no | Sentry issue environment; production deploys set this to `production`|
53
54
|`RATE_LIMIT_DEFAULT`| no | Per-IP request limit, e.g. `60/minute` (default) |
54
55
55
56
### Variables that must NOT be set in production
@@ -124,7 +125,22 @@ After the Cloud Run service is deployed:
124
125
3. Set **Serve URL** to `https://<cloud-run-url>/api/inngest`
125
126
4. Confirm **Event Key** and **Signing Key** match what was set in Cloud Run secrets
126
127
5. Click **Sync** — all three functions should appear: `rag-ingestion`, `research-run`, `outbox-dispatcher`
127
-
6. Verify `outbox-dispatcher` shows a cron trigger of `* * * * *`
128
+
6. Verify `outbox-dispatcher` shows a cron trigger of `*/2 * * * *`
129
+
130
+
Configure email alerts for terminal failures in every registered function and for no successful `outbox-dispatcher` run within six minutes. A dispatcher run returning zero events is healthy and must count as successful.
131
+
132
+
## Alerting post-deploy wiring
133
+
134
+
After creating a Sentry Python/FastAPI project, add its DSN as the `sentry_dsn` field in the existing `provider-config` JSON secret. This keeps production at six active Secret Manager versions. Then deploy and configure a Sentry email issue alert for new or regressed production issues with a 30-minute per-issue cooldown.
Verify the email channel and test notification delivery in Cloud Monitoring. The setup script is safe to rerun and updates resources with matching display names.
Copy file name to clipboardExpand all lines: docs/observability.md
+35-12Lines changed: 35 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -50,33 +50,57 @@ Available under **Cloud Run → cortex → Metrics** in the Google Cloud console
50
50
51
51
Probe outcomes appear in Cloud Logging (`resource.type="cloud_run_revision"`); a failing readiness probe logs the `/ready` 503 body, which names the failing dependency.
52
52
53
-
### Recommended alerting policy
53
+
### Production alerting baseline
54
54
55
-
The following is the documented operational policy for this deployment. Alert policies and uptime checks are created per project in Cloud Monitoring and are **not** provisioned by the deploy scripts — verify they exist in your project before relying on them.
55
+
Alert policies and the uptime check are provisioned per project by the idempotent setup script. The notification email must be verified before relying on delivery:
1.**5xx ratio** — `request_count` filtered to `response_code_class = "5xx"` above 1% of total requests over a 5-minute window. Catches elevated errors regardless of cause.
60
-
2.**p95 latency** — `request_latencies` p95 above 5 s over 10 minutes for non-SSE routes. Long-lived `/research` SSE streams inflate raw latency percentiles, so scope the alert or set the threshold with streaming in mind.
61
-
3.**Instance crash / probe failure** — log-based alert on `resource.type="cloud_run_revision"` with `severity>=ERROR` matching container exit or readiness-probe failure messages. This is the signal that `/ready` is returning 503.
62
-
4.**Uptime check** — **Cloud Monitoring → Uptime checks** against `GET /health` on the service URL, one-minute cadence, with an attached alert on failure. This detects the service being fully down even when no traffic is arriving to generate error metrics.
67
+
The script creates or updates:
63
68
64
-
Route notification channels (email, PagerDuty, Slack) per project in **Alerting → Notification channels**.
69
+
1.**Backend uptime** — checks `GET /health` each minute from the USA, Europe, and Asia-Pacific. Two failing regions for one minute opens an incident.
70
+
2.**5xx burst** — `request_count` filtered to `response_code_class = "5xx"`, aggregated across revisions. Three errors within five minutes opens an incident.
71
+
3.**Instance crash / probe failure** — log-match alert for container termination and startup, liveness, or readiness-probe failures, with a 15-minute notification rate limit.
72
+
73
+
Policies auto-close after 30 healthy minutes. The email channel is named `cortex-ops-email`; test it in **Cloud Monitoring → Alerting → Notification channels** after setup.
65
74
66
75
### How degradation is detected
67
76
68
77
Which signal fires for which failure class:
69
78
70
79
-**Critical dependency outage** (Supabase, Neo4j, LLM config) — `/ready` returns 503, Cloud Run marks the instance unready, and the probe-failure log alert fires. New revisions fail their startup probe and never receive traffic.
71
80
-**Elevated request errors** — the 5xx-ratio alert fires; drill into Cloud Logging for the failing route, and Sentry (when `SENTRY_DSN` is set) captures the exception with stack trace, error-capture only.
72
-
-**Latency regression** — the p95 alert fires; LangSmith traces show which graph node or external call slowed down.
81
+
-**Latency regression** — investigate Cloud Run latency metrics manually; long-lived SSE routes make a single global p95 alarm noisy.
73
82
-**LLM-provider failure** — surfaces as elevated 5xx plus errored runs in LangSmith/LangFuse traces; the provider's own status page confirms.
74
-
-**Ingestion backlog** — the `outbox-dispatcher` Inngest function runs every two minutes; a stall shows as failed or missing runs in the Inngest dashboard and as `document_outbox` rows stuck in `pending` in Supabase. There is no automatic alert for this today; check the Inngest dashboard when uploads stop completing.
83
+
-**Ingestion backlog** — the `outbox-dispatcher` Inngest function runs every two minutes. Configure an Inngest email alert for terminal failures and no successful run for six minutes. A zero-dispatch run is successful, so idle traffic does not alert. Final outbox delivery failures are also sent to Sentry.
75
84
-**Service fully down** — the `/health` uptime check fails within a minute even with zero user traffic.
76
85
77
86
### Error tracking
78
87
79
-
Setting `SENTRY_DSN` enables Sentry for unhandled-exception capture (error-capture only — tracing stays with LangSmith/LangFuse, PII and stack-trace locals are not sent). See [Production configuration](env-vars-production.md).
88
+
Setting `SENTRY_DSN` locally, or `sentry_dsn` inside the production `PROVIDER_CONFIG_JSON` secret, enables Sentry for unhandled and selected handled-exception capture (error-capture only — tracing stays with LangSmith/LangFuse, PII and stack-trace locals are not sent). Production uses the Cloud Run revision as the Sentry release. Configure one Sentry issue alert for a new or regressed issue in `production`, delivered by email with a 30-minute per-issue cooldown. See [Production configuration](env-vars-production.md).
89
+
90
+
Handled-exception metadata is allowlisted to operational identifiers such as run, session, job, and outbox event IDs. Prompts, chat messages, documents, tokens, and authorization values are never attached.
91
+
92
+
### Inngest alert activation
93
+
94
+
In the Inngest production environment, create email alerts for:
95
+
96
+
- terminal failure in `rag-ingestion`, `research-run`, `user-memory-refresh`, or `outbox-dispatcher`;
97
+
- no successful `outbox-dispatcher` run for six minutes.
98
+
99
+
Test the rule in a non-production Inngest environment before enabling production delivery.
100
+
101
+
### Cost guardrails
102
+
103
+
The baseline uses built-in Cloud Run metrics, one standard uptime check, one metric policy, one log-match policy, the Sentry Developer plan, and Inngest's existing alerting. At current low traffic it should remain within free allowances except for additional Secret Manager versions and future GCP metric-alert evaluation charges. Do not replace the uptime check with a synthetic monitor or deploy the benchmark Prometheus/Grafana stack to production.
80
104
81
105
## Benchmark dashboards
82
106
@@ -92,4 +116,3 @@ It provides:
92
116
- Grafana at `http://localhost:3000`
93
117
94
118
This stack is benchmark-only and is never deployed to production — Cloud Run's built-in metrics already cover the production signals (see [Production monitoring](#production-monitoring)). The k6 scenarios and reporting workflow are documented in the [load-test guide](../load-tests/README.md).
0 commit comments