WEPPcloud

← Back to usersum index

Mini Work Package: rq/api migration to rq-engine (staged deprecation)

Status: Complete (Phase 5 validation) Last Updated: 2026-01-12 Primary Areas: wepppy/microservices/rq_engine/*, wepppy/weppcloud/controllers_js/*, wepppy/weppcloud/controllers_js/utils.js, wepppy/weppcloud/controllers_js/http.js, wepppy/weppcloud/routes/rq/job_dashboard/*

Objective

Move all run-scoped RQ endpoints from Flask (/weppcloud/rq/api/*) to rq-engine (/rq-engine/api/*) and remove the Flask routes after dev validation. Complete the migration in dev before prod.

Current State Review

  • rq-engine JWT auth is in place (Phase 6 JWT mini work package complete).
  • Flask /rq/api/* and /upload/* routes are removed in dev.
  • rq-engine owns the run-scoped enqueue routes, culvert batch routes, and cancel job endpoint.
  • Controllers now target /rq-engine/api/* for queue triggers and polling.

Scope

  • Confirm rq-engine parity for all run-scoped enqueue endpoints.
  • Verify controller calls use the rq-engine base path.
  • Keep /rq/api/* and /upload/* removed after dev validation.
  • Ensure rq-engine routes stay kebab-case and callers align.
  • Verify jobstatus/jobinfo remain read-only and open (as agreed).

Non-goals

  • Changing payload schemas or response contracts beyond endpoint location.
  • Reworking auth beyond existing JWT/session behavior.

Plan

Phase 1 - Inventory + parity map (completed)

  • Enumerate all Flask /rq/api/* routes and map to rq-engine equivalents.
  • Identify endpoints still missing in rq-engine (likely run-scoped job enqueues).
  • Decide which endpoints must remain Flask-only (if any).

Flask /rq/api/* inventory (legacy; removed in dev)

Method Route Source
GET/POST /runs/<runid>/<config>/rq/api/hello_world wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/session-token wepppy/weppcloud/routes/rq/api/api.py
POST /batch/_/<batch_name>/rq/api/run-batch wepppy/weppcloud/routes/rq/api/api.py
POST /rq/api/landuse_and_soils wepppy/weppcloud/routes/rq/api/api.py
GET /rq/api/landuse_and_soils/<uuid>.tar.gz wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/fetch_dem_and_build_channels wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/set_outlet wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/build_subcatchments_and_abstract_watershed wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/build_landuse wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/build_treatments wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/build_soils wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/build_climate wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/post_dss_export_rq wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/run_wepp wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/run_wepp_watershed wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/run_omni wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/run_omni_contrasts wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/run_ash wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/run_debris_flow wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/run_rhem_rq wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/acquire_rap_ts wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/acquire_openet_ts wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/fork wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/archive wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/restore-archive wepppy/weppcloud/routes/rq/api/api.py
POST /runs/<runid>/<config>/rq/api/delete-archive wepppy/weppcloud/routes/rq/api/api.py
GET /rq/api/jobstatus/<job_id> wepppy/weppcloud/routes/rq/api/jobinfo.py
GET /rq/api/jobinfo/<job_id> wepppy/weppcloud/routes/rq/api/jobinfo.py
POST /rq/api/jobinfo wepppy/weppcloud/routes/rq/api/jobinfo.py
GET /rq/api/canceljob/<job_id> wepppy/weppcloud/routes/rq/api/jobinfo.py
POST /rq/api/run-sync wepppy/weppcloud/routes/run_sync_dashboard/run_sync_dashboard.py
GET /rq/api/run-sync/status wepppy/weppcloud/routes/run_sync_dashboard/run_sync_dashboard.py

Flask /upload/* inventory (legacy; removed in dev)

Method Route Source
GET /upload/health wepppy/weppcloud/routes/upload_bp.py
POST /upload/runs/<runid>/<config>/tasks/upload_cli/ wepppy/weppcloud/routes/upload_bp.py
POST /upload/runs/<runid>/<config>/tasks/upload_sbs/ wepppy/weppcloud/routes/upload_bp.py
POST /upload/runs/<runid>/<config>/tasks/upload_cover_transform wepppy/weppcloud/routes/upload_bp.py
POST /upload/huc-fire/tasks/upload_sbs/ wepppy/weppcloud/routes/upload_bp.py
POST /upload/batch/_/<batch_name>/upload-geojson wepppy/weppcloud/routes/upload_bp.py
POST /upload/batch/_/<batch_name>/upload-sbs-map wepppy/weppcloud/routes/upload_bp.py
POST /upload/runs/<runid>/<config>/rq/api/build_landuse wepppy/weppcloud/routes/upload_bp.py
POST /upload/runs/<runid>/<config>/rq/api/build_treatments wepppy/weppcloud/routes/upload_bp.py
POST /upload/runs/<runid>/<config>/rq/api/run_ash wepppy/weppcloud/routes/upload_bp.py
POST /upload/runs/<runid>/<config>/rq/api/run_omni wepppy/weppcloud/routes/upload_bp.py
POST /upload/runs/<runid>/<config>/rq/api/run_omni_contrasts wepppy/weppcloud/routes/upload_bp.py

rq-engine routes already present

Method Route Source
GET /rq-engine/api/jobstatus/{job_id} wepppy/microservices/rq_engine/job_routes.py
GET /rq-engine/api/jobinfo/{job_id} wepppy/microservices/rq_engine/job_routes.py
POST /rq-engine/api/jobinfo wepppy/microservices/rq_engine/job_routes.py
POST /rq-engine/api/canceljob/{job_id} wepppy/microservices/rq_engine/job_routes.py
POST /rq-engine/api/culverts-wepp-batch/ wepppy/microservices/rq_engine/culvert_routes.py
POST /rq-engine/api/culverts-wepp-batch/{batch_uuid}/retry/{point_id} wepppy/microservices/rq_engine/culvert_routes.py
POST /rq-engine/api/landuse-and-soils wepppy/microservices/rq_engine/landuse_soils_routes.py
GET /rq-engine/api/landuse-and-soils/{uuid}.tar.gz wepppy/microservices/rq_engine/landuse_soils_routes.py
POST /rq-engine/api/batch/_/{batch_name}/run-batch wepppy/microservices/rq_engine/batch_routes.py
POST /rq-engine/api/runs/<runid>/<config>/build-landuse wepppy/microservices/rq_engine/landuse_routes.py
POST /rq-engine/api/runs/<runid>/<config>/build-soils wepppy/microservices/rq_engine/soils_routes.py
POST /rq-engine/api/runs/<runid>/<config>/build-climate wepppy/microservices/rq_engine/climate_routes.py
POST /rq-engine/api/runs/<runid>/<config>/build-treatments wepppy/microservices/rq_engine/treatments_routes.py
POST /rq-engine/api/runs/<runid>/<config>/post-dss-export-rq wepppy/microservices/rq_engine/dss_export_routes.py
POST /rq-engine/api/runs/<runid>/<config>/run-wepp wepppy/microservices/rq_engine/wepp_routes.py
POST /rq-engine/api/runs/<runid>/<config>/run-wepp-watershed wepppy/microservices/rq_engine/wepp_routes.py
POST /rq-engine/api/runs/<runid>/<config>/run-omni wepppy/microservices/rq_engine/omni_routes.py
POST /rq-engine/api/runs/<runid>/<config>/run-omni-contrasts wepppy/microservices/rq_engine/omni_routes.py
POST /rq-engine/api/runs/<runid>/<config>/run-ash wepppy/microservices/rq_engine/ash_routes.py
POST /rq-engine/api/runs/<runid>/<config>/run-debris-flow wepppy/microservices/rq_engine/debris_flow_routes.py
POST /rq-engine/api/runs/<runid>/<config>/run-rhem wepppy/microservices/rq_engine/rhem_routes.py
POST /rq-engine/api/runs/<runid>/<config>/acquire-rap-ts wepppy/microservices/rq_engine/rap_ts_routes.py
POST /rq-engine/api/runs/<runid>/<config>/acquire-openet-ts wepppy/microservices/rq_engine/openet_ts_routes.py
POST /rq-engine/api/runs/<runid>/<config>/fetch-dem-and-build-channels wepppy/microservices/rq_engine/watershed_routes.py
POST /rq-engine/api/runs/<runid>/<config>/set-outlet wepppy/microservices/rq_engine/watershed_routes.py
POST /rq-engine/api/runs/<runid>/<config>/build-subcatchments-and-abstract-watershed wepppy/microservices/rq_engine/watershed_routes.py
POST /rq-engine/api/runs/<runid>/<config>/fork wepppy/microservices/rq_engine/fork_archive_routes.py
POST /rq-engine/api/runs/<runid>/<config>/archive wepppy/microservices/rq_engine/fork_archive_routes.py
POST /rq-engine/api/runs/<runid>/<config>/restore-archive wepppy/microservices/rq_engine/fork_archive_routes.py
POST /rq-engine/api/runs/<runid>/<config>/delete-archive wepppy/microservices/rq_engine/fork_archive_routes.py
POST /rq-engine/api/run-sync wepppy/microservices/rq_engine/run_sync_routes.py
GET /rq-engine/api/run-sync/status wepppy/microservices/rq_engine/run_sync_routes.py
POST /rq-engine/api/runs/<runid>/<config>/tasks/upload-cli/ wepppy/microservices/rq_engine/upload_climate_routes.py
POST /rq-engine/api/runs/<runid>/<config>/tasks/upload-sbs/ wepppy/microservices/rq_engine/upload_disturbed_routes.py
POST /rq-engine/api/runs/<runid>/<config>/tasks/upload-cover-transform wepppy/microservices/rq_engine/upload_disturbed_routes.py
POST /rq-engine/api/huc-fire/tasks/upload-sbs/ wepppy/microservices/rq_engine/upload_huc_fire_routes.py
POST /rq-engine/api/batch/_/<batch_name>/upload-geojson wepppy/microservices/rq_engine/upload_batch_runner_routes.py
POST /rq-engine/api/batch/_/<batch_name>/upload-sbs-map wepppy/microservices/rq_engine/upload_batch_runner_routes.py

Phase 2 - rq-engine endpoint parity (completed)

  • Implement missing rq-engine endpoints with identical request/response payloads.
  • Reuse existing RQ job enqueuing helpers where possible.
  • Ensure auth aligns with the JWT model (scopes, run claims, denylist).

Parity plan (proposed rq-engine route modules)

Module Routes Notes
job_routes.py jobstatus/jobinfo/canceljob Already present.
culvert_routes.py culvert batch submit/retry Already present.
session_routes.py /rq-engine/api/runs/<runid>/<config>/session-token Port session token issuance + Redis marker.
batch_routes.py /rq-engine/api/batch/_/<batch_name>/run-batch Port batch runner enqueue logic (JWT admin required).
landuse_soils_routes.py /rq-engine/api/landuse-and-soils + tar download Port landuse/soils bundle flow.
watershed_routes.py fetch-dem-and-build-channels, set-outlet, build-subcatchments-and-abstract-watershed Run-scoped watershed pipeline.
landuse_routes.py build-landuse Run-scoped RQ enqueue.
soils_routes.py build-soils Run-scoped RQ enqueue.
climate_routes.py build-climate Run-scoped RQ enqueue.
treatments_routes.py build-treatments Implemented (rq-engine run-scoped enqueue).
dss_export_routes.py post-dss-export-rq Implemented (rq-engine run-scoped enqueue).
wepp_routes.py run-wepp, run-wepp-watershed Implemented (rq-engine run-scoped enqueue + response parity).
omni_routes.py run-omni, run-omni-contrasts Implemented (upload-capable endpoints).
ash_routes.py run-ash Implemented (upload-capable endpoint).
debris_flow_routes.py run-debris-flow Implemented (run-scoped RQ enqueue).
rhem_routes.py run-rhem Implemented (run-scoped RQ enqueue).
rap_ts_routes.py acquire-rap-ts Implemented (run-scoped RQ enqueue).
openet_ts_routes.py acquire-openet-ts Implemented (run-scoped RQ enqueue).
fork_archive_routes.py fork, archive, restore-archive, delete-archive Implemented.
run_sync_routes.py /rq-engine/api/run-sync, /rq-engine/api/run-sync/status Implemented (admin role required).
debug_routes.py hello_world Optional; decide to drop vs keep as a smoke endpoint.

Implementation notes

  • Prefer moving shared logic into wepppy/rq/* helpers or new shared modules to avoid importing Flask handlers into rq-engine.
  • Keep routers in separate files and include them in wepppy/microservices/rq_engine/__init__.py.
  • Use kebab-case for all new rq-engine route paths and update controller call sites (no new underscores).
  • Batch Runner run submissions now require an admin JWT; the manage page injects a rqEngineToken bootstrap value for the controller.

Phase 2.5 - Upload proxy migration (completed)

  • Port upload routes to rq-engine under /rq-engine/api/* with identical payloads.
  • Update controller calls to use /rq-engine/api/* upload endpoints (drop /upload usage).
  • Drop the /upload/* proxy entirely (Caddy rule removed).

Upload parity plan (rq-engine route groups)

Group Routes Notes
upload_climate_routes.py /rq-engine/api/runs/<runid>/<config>/tasks/upload-cli/ Implemented.
upload_disturbed_routes.py /rq-engine/api/runs/<runid>/<config>/tasks/upload-sbs/, /rq-engine/api/runs/<runid>/<config>/tasks/upload-cover-transform Implemented.
upload_huc_fire_routes.py /rq-engine/api/huc-fire/tasks/upload-sbs/ Implemented (JWT user token required).
upload_batch_runner_routes.py /rq-engine/api/batch/_/<batch_name>/upload-geojson, /rq-engine/api/batch/_/<batch_name>/upload-sbs-map Implemented (admin role required).

Upload implementation notes

  • Extract request-agnostic helpers from Flask upload handlers (avoid importing Flask view functions into rq-engine).
  • Replace Flask request.files usage with FastAPI UploadFile handling.
  • Keep timeout behavior on /rq-engine* (already long in Caddy); /upload* routing is removed.

Phase 3 - Controller migration (completed)

  • Add a run-scoped helper that targets rq-engine (e.g., url_for_rq_engine_run()).
  • Update controllers that call rq/api/* to use the new helper.

Phase 4 - Remove Flask /rq/api/* and /upload/* (completed)

  • Delete /rq/api/* and /upload/* routes once rq-engine parity + controller migration are validated in dev.
  • Remove any route imports/registrations so hot reload startup stays clean.
  • Update any docs/tests that still reference /rq/api/* or /upload/*.

Phase 5 - Validation + cleanup plan (completed)

  • Verify UI workflows: enqueue + polling + cancel + results display.
  • Confirm jobstatus/jobinfo remain reachable without auth tokens.
  • Add tests for rq-engine parity (including upload routes).
  • Draft a follow-on removal checklist once prod is migrated.
  • Manual smoke test completed in dev; schedule a fresh agent review before removing legacy routes in prod.
  • Jobstatus/jobinfo spot check (2026-01-13): /rq-engine/api/jobstatus/4e8a87af-49c4-4eac-8385-dfc2a6843406 and /rq-engine/api/jobinfo/4e8a87af-49c4-4eac-8385-dfc2a6843406 returned status=finished for run brocaded-confection with no exc_info in children.

Follow-on removal checklist (post-prod migration)

  • Confirm there are still no external clients relying on /rq/api/* or /upload/* before removing any compatibility shims.
  • Remove legacy Flask upload endpoints once confirmed unused:
    • wepppy/weppcloud/routes/nodb_api/climate_bp.py (/runs/<runid>/<config>/tasks/upload_cli/)
    • wepppy/weppcloud/routes/nodb_api/disturbed_bp.py (/runs/<runid>/<config>/tasks/upload_sbs/, /runs/<runid>/<config>/tasks/upload_cover_transform)
    • wepppy/weppcloud/routes/huc_fire.py (/huc-fire/tasks/upload_sbs/)
    • wepppy/weppcloud/routes/batch_runner/batch_runner_bp.py (/batch/_/<batch_name>/upload-geojson, /batch/_/<batch_name>/upload-sbs-map)
  • Retire legacy /rq/api replay fallbacks once old captures are archived (wepppy/profile_recorder/*).
  • Sweep archival docs for /rq/api or /upload mentions if the historical notes are no longer needed.

Exit Criteria

  • All UI controller calls use /rq-engine/api/* for rq endpoints.
  • rq-engine covers the full /rq/api/* surface with matching payloads.
  • Flask /rq/api/* routes removed and no longer imported.
  • Upload routes are handled under /rq-engine/api/* and clients no longer rely on /upload.
  • Dev environment validated; ready for prod deployment.

Risks / Notes

  • Removing Flask endpoints is a hard cut; dev validation must cover all controllers.
  • Ensure any new helper preserves url_for_run() semantics so run-scoped URLs stay correct.
  • Upload endpoints must continue to honor long timeouts (covered by /rq-engine reverse proxy).
  • Keep rq-engine routes organized in separate modules (avoid a single monolithic router file).
  • Set SESSION_COOKIE_PATH=/ so rq-engine endpoints can read Flask session cookies.

Open Questions

  • Confirm rq-engine base path for browser use: same-origin /rq-engine vs direct :8042.
  • Should rq-engine be exposed outside the default /rq-engine reverse proxy path?