Skip to content
Operations

Operations

HTTP endpoints

EndpointPurpose
POST /webhookForgejo push events
GET /healthzLiveness: 200 while the process serves HTTP
GET /readyzReadiness: 503 before serving and once shutdown begins, so load balancers stop sending webhooks
GET /metricsPrometheus metrics

Metrics

forgemirror records metrics with OpenTelemetry and exposes them in the Prometheus format. Go runtime (go_*) and process (process_*) metrics are included as well.

MetricTypeLabelsMeaning
forge_mirror_operations_totalcountertarget, statusMirror operations per target; status is success or failure
forge_mirror_duration_secondshistogramtargetDuration of each push to a target; buckets from 0.5 s to 10 min
forge_mirror_webhook_requests_totalcounteroutcomeWebhook requests by outcome
forge_mirror_active_operationsgaugeMirror runs in progress
target_infogaugeservice_name, service_versionBuild information

A failed clone counts as a failure for every target, because none of them could be updated.

Example alerts:

groups:
  - name: forgemirror
    rules:
      - alert: ForgemirrorTargetFailing
        expr: increase(forge_mirror_operations_total{status="failure"}[30m]) > 0
        labels: { severity: warning }
        annotations:
          summary: "Mirroring to {{ $labels.target }} fails"
      - alert: ForgemirrorWebhookUnauthorized
        expr: increase(forge_mirror_webhook_requests_total{outcome="unauthorized"}[15m]) > 0
        labels: { severity: warning }
        annotations:
          summary: "Webhook signature mismatch; check webhook.secret"

Logs

forgemirror writes structured logs to stderr. They are JSON by default; set log.format: text for logfmt-style lines. Mirror events carry repository, ref, delivery, and per target also target, outcome and duration.

MessageLevelMeaning
mirror started / mirror finishedinfoOne run for one repository
target mirroredinfoPush to one target succeeded
target failederrorPush to one target failed; includes git’s output
mirror failederrorClone failed; no target was updated
mirror already running; queued one follow-up runinfoPush arrived during a run, so a follow-up run is coalesced
shutting down; event droppedwarnPush arrived after shutdown began
shutting down; queued follow-up run droppedwarnA coalesced follow-up run was not started because of shutdown

git output in logs and errors is redacted: tokens and authorization headers show up as [REDACTED].

Graceful shutdown

On SIGTERM or SIGINT:

  1. /readyz returns 503 and the listener stops accepting connections.
  2. Open webhook requests are answered.
  3. Running mirrors finish. Queued follow-up runs and new pushes are dropped and logged; the next push after the restart mirrors the latest state.
  4. When server.shutdown_timeout (60 s by default) runs out, git processes are killed and the process exits.

The phases share one budget. Keep the orchestrator’s kill timeout above it: terminationGracePeriodSeconds (Kubernetes), stop_grace_period (Compose), or TimeoutStopSec (systemd).

Troubleshooting

SymptomCause and fix
Forgejo delivery fails with “host not allowed”Allow forgemirror in [webhook] ALLOWED_HOST_LIST; see Forgejo webhook
401 responseswebhook.secret and the secret in Forgejo differ
415 responsesWebhook content type is form-encoded; set application/json
200 not mirrored: …A filter rule excludes the push; the body names the rule
target failed … Repository not foundTarget repository does not exist, or the URL template renders a different name
target failed … 403 / Authentication failedToken lacks push permission or has expired; GitHub fine-grained tokens need Contents: read and write
target failed … protected branchForce pushes are blocked on the target; allow them for the mirror account, because mirroring rewrites history like the source
mirror failed on private repositoriessource.token is missing or lacks read access
Pod evictedClones exceed the /work emptyDir sizeLimit; raise it
Last updated on