mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-08-26 17:31:37 +00:00
* MVUM Layer 0: spatial index foundation Additive only — no routing logic, no response-format, no Valhalla changes. - mvum.py: add MVUMSpatialIndex. Loads mvum_roads + mvum_trails from navi.db (read-only), decodes the pure-WKB shape blobs with shapely, builds a shapely.strtree.STRtree, and keeps a parallel list of full feature records (all columns minus the blob, plus the parsed geometry) with a by_id lookup. Exposes query_bbox(min_lat,min_lon,max_lat,max_lon) and query_buffered_line(coords, tolerance_m) returning candidate records (coarse bbox + buffer; full parallelism filter is a TODO for PR-B). Reports road_count, trail_count, bbox, build_time_seconds, memory_estimate_mb (RSS delta). - app.py: build the index once per process (singleton) at service init; stored on app.config[MVUM_SPATIAL_INDEX]. Failure is logged and degrades to None. - admin.py: GET /api/admin/mvum-spatial/info (Authentik-gated, read-only) returning the counts/bbox/build-time/memory stats. - tests/test_mvum_spatial.py: index loads, query_bbox returns Boise-area features, query_buffered_line returns a feature, admin endpoint returns counts. Diagnostic before coding (read-only): roads_with_shape=150568/null=68, trails_with_shape=21995/null=6746 (green), shape blobs are pure WKB MultiLineString. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Fix lat-aware buffer + count WKB parse failures - query_buffered_line: replace the static _DEG_PER_M with _buffer_degrees_for_meters(), which scales longitude degrees by cos(lat) and uses the larger lat/lon equivalent; buffer at the polyline avg latitude. Early-return [] for empty coords. - _load_table: count WKB parse failures and logger.warning once per table when > 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Matt <mj@k7zvx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
59 lines
1.6 KiB
Python
59 lines
1.6 KiB
Python
"""navi-offroute Flask application factory + gunicorn entry.
|
|
|
|
Gunicorn entry:
|
|
gunicorn 'services.navi_offroute.app:create_app()' --bind 127.0.0.1:8428 --workers 2
|
|
"""
|
|
import time
|
|
|
|
from flask import Flask
|
|
|
|
from shared.git_sha import git_short_sha
|
|
|
|
from . import offroute_route, admin
|
|
from .mvum import MVUMSpatialIndex
|
|
|
|
# Process-wide singleton: build the MVUM spatial index once per process (per gunicorn
|
|
# worker in prod; once across create_app() calls in tests), not once per app instance.
|
|
_MVUM_INDEX = None
|
|
|
|
|
|
def _get_mvum_index():
|
|
global _MVUM_INDEX
|
|
if _MVUM_INDEX is None:
|
|
_MVUM_INDEX = MVUMSpatialIndex()
|
|
return _MVUM_INDEX
|
|
|
|
|
|
|
|
def create_app():
|
|
app = Flask(__name__)
|
|
|
|
app.config['VERSION'] = git_short_sha()
|
|
app.config['METRICS'] = {
|
|
'start_time': time.time(),
|
|
'request_count': 0,
|
|
'last_error_at': None,
|
|
}
|
|
|
|
@app.before_request
|
|
def _count_request():
|
|
app.config['METRICS']['request_count'] += 1
|
|
|
|
@app.after_request
|
|
def _track_errors(response):
|
|
if response.status_code >= 500:
|
|
app.config['METRICS']['last_error_at'] = time.strftime(
|
|
'%Y-%m-%dT%H:%M:%SZ', time.gmtime()
|
|
)
|
|
return response
|
|
|
|
# Load the MVUM spatial index once at service init (logs its own load line).
|
|
try:
|
|
app.config['MVUM_SPATIAL_INDEX'] = _get_mvum_index()
|
|
except Exception as e:
|
|
app.logger.warning("MVUM spatial index failed to load: %s", e)
|
|
app.config['MVUM_SPATIAL_INDEX'] = None
|
|
|
|
app.register_blueprint(offroute_route.bp)
|
|
app.register_blueprint(admin.bp)
|
|
return app
|