edge-endpoint can be configured by python-sdk#359
Open
timmarkhuff wants to merge 36 commits intomainfrom
Open
Conversation
4ac4b37 to
51f7da8
Compare
timmarkhuff
commented
Mar 27, 2026
| cp deploy/helm/groundlight-edge-endpoint/files/default-edge-config.yaml $EDGE_CONFIG_FILE | ||
| sed -i "s/detector_id: \"\"/detector_id: \"$DETECTOR_ID\"/" $EDGE_CONFIG_FILE | ||
| sed -i "s/refresh_rate: 60/refresh_rate: $REFRESH_RATE/" $EDGE_CONFIG_FILE | ||
| cat > $EDGE_CONFIG_FILE <<EOF |
Contributor
Author
There was a problem hiding this comment.
We no longer have default-edge-config.yaml (since we rely on Pydantic defaults), so we need to construct a config from scratch here.
…ight/edge-endpoint into tim/edge-accepts-config-requests
…ight/edge-endpoint into tim/edge-accepts-config-requests
brandon-wada
approved these changes
Apr 1, 2026
Collaborator
brandon-wada
left a comment
There was a problem hiding this comment.
I'm reminded how rusty I am on the edge code. At least all the parts look like they make sense to me
| detector is responding to health checks. | ||
| """ | ||
| config = EdgeConfigManager.active() | ||
| detector_ids = [d.detector_id for d in config.detectors if d.detector_id] |
Collaborator
There was a problem hiding this comment.
When is detector_id falsey?
| subPath: dummy-nginx.conf | ||
| - name: edge-endpoint-persistent-volume | ||
| mountPath: /opt/groundlight/edge/sqlite | ||
| - name: edge-endpoint-persistent-volume |
Collaborator
There was a problem hiding this comment.
Do we want to reuse the existing volume for this?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds HTTP endpoints for reading and modifying the edge endpoint configuration at runtime, without requiring a Helm redeploy. A Python SDK companion PR provides the client-side methods.
New endpoints:
GET /edge-config-- returns the activeEdgeEndpointConfigPUT /edge-config-- replaces the active config (diffs against current state, adds/removes detector pods accordingly)GET /edge-detector-readiness-- reports which configured detectors have inference pods ready to serveKey design decisions
Config as a shared file on PVC
Multiple uvicorn workers cannot share in-memory state. The active config is persisted to a YAML file on the existing PVC (
/opt/groundlight/edge/config/active-edge-config.yaml). Workers read it via an mtime-based cache (EdgeConfigManager.active()), which callsos.path.getmtimeon each access and only re-parses when the file has changed. This gives cross-worker consistency with negligible overhead.Config loading priority at startup
EdgeConfigManager.load_startup_config()checks sources in order:EDGE_CONFIGenv var (for Docker/test setups/Balena deployments)Detector reconciliation
PUT /edge-configtriggersreconcile_config(), which:compute_detector_diff)pending_deletionin the DBThe
inference-model-updaterpicks up these DB changes on its next loop iteration -- deleting pods forpending_deletionrecords, then creating pods for new ones. This could cause the config update process to take a bit longer than necessary (because we have to wait for the refresh loop to occur). I thought about adding logic to make the inference-model-updater poll for config updates while it waits, and terminate early if it sees one. In the end, I decided to not add that (yet). YAGNI.Deprecation of default-edge-config.yaml
The static
deploy/helm/groundlight-edge-endpoint/files/default-edge-config.yamlhas been removed. Default config is now defined by Pydantic model defaults in thepython-sdk. When no config file is provided to Helm,_helpers.tplgenerates an empty YAML object, and the system uses Pydantic defaults.Notable refactorings
EdgeConfigManager(new, replacesedge_config_loader.py): Singleton-style class with class methods for config lifecycle --load_startup_config(),save(),active(),detector_configs(),detector_config().EdgeInferenceManagersimplification: Removed storeddetector_inference_configs,inference_client_urls,oodd_inference_client_urls,min_times_between_escalations, and the 30-second scheduler poll. The manager now computes pod URLs on the fly from detector IDs and reads config fromEdgeConfigManager.active(). Onlylast_escalation_timesremains as runtime state.naming.py(new): Extractedget_edge_inference_service_nameandget_edge_inference_model_nameout ofedge_inference.pyto break a circular import betweenedge_inference.pyandedge_config_manager.py.pending_deletioncolumn: Added to theInferenceDeploymentDB model. The column has a server default ofFalse, so existing databases are compatible without migration.Authentication
These new endpoints are unauthenticated, consistent with all other non-inference endpoints on the edge endpoint (status page, metrics, health checks). The edge endpoint assumes a trusted local network.
GET /edge-configandGET /edge-detector-readinessare comparable in sensitivity to the existing status page andmetrics.json, which already expose detector IDs, model versions, and readiness.PUT /edge-configis the only unauthenticated write endpoint that modifies system state. An attacker with network access could add or remove detectors. This is an accepted tradeoff under the trusted-network assumption. If edge endpoints are ever exposed to untrusted networks, this endpoint should be the first to get auth.Release strategy
This PR must be deployed before the companion SDK PR (
python-sdk0.26.0). The SDK'sgl.edge.*methods call endpoints that only exist after this PR is deployed. Releasing the SDK first would cause those methods to 404.The edge endpoint's
groundlightdependency does not need to change for this PR -- it uses SDK features already available in0.25.x. However, once the SDK is released at0.26.0, a follow-up bump to>=0.26.0, <0.27.0is recommended.Tests
test/api/test_edge_config.py: GET returns 200, PUT validates body (422 on invalid, 200 on valid)test/core/test_edge_config_manager.py:compute_detector_diff(6 cases),apply_detector_changes(3 cases),EdgeConfigManager(save/load/active roundtrip, mtime caching, startup priority, detector config lookups)Load Testing
This PR touches some code in the hot path of inference (in what I hope is a trivial way). To ensure that I am not introducing any performance regressions, I performed the following benchmark. The results appear nearly identical, each test achieving a "Max Steady RPS" of 30 with the
countstep-yolox-trackingpipeline.With changes:

Before changes:
