Fix self-hosted checker and workflow routing#1976
Fix self-hosted checker and workflow routing#1976aiokaizen wants to merge 3 commits intoopenstatusHQ:mainfrom
Conversation
|
@aiokaizen is attempting to deploy a commit to the OpenStatus Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| } | ||
|
|
||
| func UpdateStatus(ctx context.Context, updateData UpdateData) error { | ||
|
|
There was a problem hiding this comment.
openstatus/apps/checker/cmd/server/main.go
Line 175 in 55f2e53
We should do something like this instead
|
Also for self host it's easier to use private location |
There was a problem hiding this comment.
Pull request overview
This PR fixes self-hosted deployments by decoupling checker/workflow routing from OpenStatus cloud infrastructure and disabling Cloud Tasks usage when GCP config isn’t present.
Changes:
- Added explicit self-host routing via env vars (checker/workflows base URLs + region) and updated API/server to call local checker endpoints.
- Updated workflows to avoid initializing/using Google Cloud Tasks in self-host mode or without valid GCP config, and added a direct HTTP dispatch path to the checker.
- Updated Docker Compose and env examples to include a Redis REST shim and self-host service wiring.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/api/src/router/checker.ts | Routes checker calls to local base URL in self-host mode and normalizes region/base URL handling. |
| apps/server/src/routes/v1/check/http/post.ts | Uses self-host checker routing for test runs instead of hosted Fly endpoints. |
| apps/server/src/libs/checker/utils.ts | Builds checker URLs pointing to local checker service in self-host mode. |
| apps/workflows/src/env.ts | Adds self-host routing env variables and SELF_HOST flag to workflows config. |
| apps/workflows/src/cron/monitor.ts | Lazily constructs Cloud Tasks context only when configured; skips lifecycle workflow scheduling if unavailable. |
| apps/workflows/src/cron/checker.ts | Adds direct (non-Cloud-Tasks) dispatch to checker for self-host / no-GCP configs. |
| apps/checker/checker/update.go | Posts status updates directly back to workflows in self-host/custom workflows URL mode. |
| docker-compose.yaml | Adds redis + redis-http services and wires new self-host env vars across services including checker. |
| docker-compose.github-packages.yaml | Same as above but for GitHub Packages images. |
| .env.docker.example | Updates env guidance for self-host routing and Redis REST shim defaults. |
| .env.docker-lightweight.example | Adds missing self-host routing + Redis REST shim variables. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| c: Context, | ||
| ) { | ||
| const timestamp = Date.now(); | ||
| const selfHostRegion = env().CHECKER_REGION as Region; |
| for (const row of monitors.data) { | ||
| const result = await db | ||
| .select() | ||
| .from(monitorStatusTable) | ||
| .where(eq(monitorStatusTable.monitorId, row.id)) | ||
| .all(); | ||
| const monitorStatus = z.array(selectMonitorStatusSchema).safeParse(result); |
| ); | ||
| } | ||
|
|
||
| const allRequests = await Promise.allSettled(allResult); |
| const selfHostRegion = env().CHECKER_REGION as Region; | ||
|
|
| const response = await fetch( | ||
| `${getCheckerBaseUrl()}/checker/${row.jobType}?monitor_id=${row.id}`, | ||
| { | ||
| method: "POST", | ||
| headers: { | ||
| Authorization: `Basic ${env().CRON_SECRET}`, | ||
| "Content-Type": "application/json", | ||
| }, | ||
| body: JSON.stringify(payload), | ||
| }, | ||
| ); |
| payloadBuf := new(bytes.Buffer) | ||
|
|
||
| if os.Getenv("SELF_HOST") == "true" || os.Getenv("OPENSTATUS_WORKFLOWS_URL") != "" { | ||
| if err := json.NewEncoder(payloadBuf).Encode(updateData); err != nil { | ||
| log.Ctx(ctx).Error().Err(err).Msg("error while encoding update payload") | ||
| return err | ||
| } | ||
|
|
||
| req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, payloadBuf) | ||
| if err != nil { | ||
| log.Ctx(ctx).Error().Err(err).Msg("error while creating update request") | ||
| return err | ||
| } | ||
| req.Header.Set("Authorization", basic) | ||
| req.Header.Set("Content-Type", "application/json") | ||
|
|
||
| res, err := http.DefaultClient.Do(req) | ||
| if err != nil { | ||
| log.Ctx(ctx).Error().Err(err).Msg("error while posting update status directly") | ||
| return err | ||
| } | ||
| defer res.Body.Close() | ||
|
|
||
| if res.StatusCode < 200 || res.StatusCode >= 300 { | ||
| return fmt.Errorf("direct updateStatus failed with status %d", res.StatusCode) | ||
| } | ||
|
|
||
| return nil | ||
| } |
| req.Header.Set("Authorization", basic) | ||
| req.Header.Set("Content-Type", "application/json") | ||
|
|
||
| res, err := http.DefaultClient.Do(req) |
| - "8079:80" | ||
| environment: | ||
| - SRH_MODE=env | ||
| - SRH_TOKEN=${UPSTASH_REDIS_REST_TOKEN:-replace-with-a-long-random-secret} |
| function isSelfHost() { | ||
| return process.env.SELF_HOST === "true"; | ||
| } | ||
|
|
||
| function getCheckerBaseUrl() { | ||
| return (process.env.CHECKER_BASE_URL || "http://checker:8080").replace( | ||
| /\/$/, | ||
| "", | ||
| ); | ||
| } | ||
|
|
||
| function getCheckerRegion(region: string) { |
…table. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
actually local.