feat: split k8s manifests and add /metrics endpoint #5
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ldraney/linkedin-scheduler-remote!5
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "3-align-k8s-manifests-add-metrics"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Split the multi-document
deployment.yamlinto one-resource-per-file convention and add a hand-rolled Prometheus/metricsendpoint so the existing ServiceMonitor stops hitting 404.Changes
k8s/deployment.yaml-- removed inline Service and PVC documents, now contains only the Deployment resourcek8s/service.yaml-- new file, extracted Service (port 8000, selector app: linkedin-scheduler-remote)k8s/pvc.yaml-- new file, extracted PVC (linkedin-mcp-data, 100Mi, local-path)k8s/kustomization.yaml-- added service.yaml and pvc.yaml to resources list (now lists all four: deployment, service, pvc, servicemonitor)server.py-- added/metricsGET endpoint returning Prometheus text exposition format (uptime_seconds gauge, http_requests_total counter) with request-counting middlewareTest Plan
ruff check .-- passesruff format --check .-- passeskubectl kustomize k8s/-- renders four separate resources (Deployment, Service, PVC, ServiceMonitor)curl http://localhost:8000/metrics-- returns Prometheus text format with uptime_seconds and http_requests_totalReview Checklist
Related Notes
Closes #3
QA Review -- PR #5
Scope Check
PR modifies exactly the 5 files listed in issue #3's File Targets. No unrelated changes. No files from the "do not touch" list were modified (.woodpecker.yml, Dockerfile, servicemonitor.yaml, pyproject.toml).
k8s Manifests
deployment.yaml -- Clean. Only the Deployment resource remains. No
---separators, no inline Service or PVC.service.yaml -- Correct extraction. Port name
httpmatches the ServiceMonitor'sport: httpendpoint reference. Selectorapp: linkedin-scheduler-remoteis consistent.pvc.yaml -- Correct extraction. Name
linkedin-mcp-data, 100Mi,local-pathstorageClass, ReadWriteOnce.kustomization.yaml -- Lists all four resources: deployment.yaml, service.yaml, pvc.yaml, servicemonitor.yaml. Verified via
kubectl kustomize .rendering four separate resources./metrics Endpoint
text/plain; version=0.0.4; charset=utf-8)uptime_seconds(gauge) andhttp_requests_total(counter) -- meets minimum requirement from acceptance criteriathreading.LockObservations (non-blocking)
_start_timeset at module load -- uptime_seconds measures from import time rather than server start. The delta is negligible (sub-second) and this is a common pattern.http_requests_total. This is standard behavior and expected.globalkeyword in middleware class -- functional and correct for the module-level variable pattern used here.Acceptance Criteria Checklist
k8s/deployment.yamlcontains only the Deployment resourcek8s/service.yamlexists with correct Service resourcek8s/pvc.yamlexists with correct PVC resourcek8s/kustomization.yamllists all four resourcesserver.pyexposes GET /metrics in Prometheus text formatVERDICT: APPROVE
No blocking issues found. Clean extraction of k8s resources and a solid hand-rolled /metrics implementation. Ready to merge.
PR #5 Review
DOMAIN REVIEW
Tech stack: Python (Starlette/uvicorn), Kubernetes manifests (Kustomize), Prometheus metrics.
K8s manifest split (k8s/)
The extraction of Service and PVC from the multi-document
deployment.yamlintok8s/service.yamlandk8s/pvc.yamlis byte-for-byte identical to the originals.kustomization.yamlcorrectly lists all four resources. Clean, mechanical refactor -- no issues.Prometheus /metrics endpoint (server.py)
uptime_seconds(gauge with_secondssuffix),http_requests_total(counter with_totalsuffix).# HELPand# TYPEannotations are well-formed.text/plain; version=0.0.4; charset=utf-8is the correct Prometheus text exposition format._start_time = time.monotonic()is the right clock choice (monotonic, not wall-clock)._http_request_countis correctly used for both reads and writes -- safe given theBaseHTTPMiddlewareasync dispatch runs in a thread context.app.routes.insert(0, Route(...))ensures/metricstakes precedence over any catch-all MCP routes. Direct list mutation is slightly fragile but appropriate here sincebuild_app_with_middlewarereturns a fresh Starlette app each time.mcp/uvicorn-- not explicitly declared inpyproject.tomlbut reliably present. Acceptable for an internal service.BLOCKERS
None.
On test coverage: This PR adds ~30 lines of new Python (metrics endpoint + counting middleware). The repo has zero test files and CI only runs ruff lint/format -- that is a pre-existing condition, not a regression introduced by this PR. The new code is infrastructure plumbing (Prometheus text format output and a request counter), not business logic. Requiring test coverage for this PR alone when the entire repo is untested would be scope creep. That said, a follow-up issue to establish a basic test harness for this repo would be valuable.
NITS
Metrics endpoint counts its own scrapes. The
_CountMiddlewareincrements_http_request_countfor every request includingGET /metrics. With a 30s ServiceMonitor scrape interval, this adds ~2880 phantom requests/day to the counter. Consider excluding the/metricspath from the counter:Missing trailing newline in metrics output. The Prometheus exposition format spec requires the response to end with a newline. The current
lineslist ends with""which produces a trailing\nvia"\n".join(lines)-- so this actually IS correct. Disregard.[project.urls]still points to GitHub. Inpyproject.tomllines 34-36, Repository and Issues URLs point togithub.comrather than the Forgejo instance. Pre-existing, not introduced by this PR, but worth noting for a future cleanup.SOP COMPLIANCE
3-align-k8s-manifests-add-metricsreferences issue #3)Closes #3present.envfiles in diff## Relatedsection referencing a plan slug -- acceptable since this is a standalone repo without an associated pal-e-docs planPROCESS OBSERVATIONS
/metricsendpoint, which is easy to test in isolation without LinkedIn OAuth).VERDICT: APPROVED