This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

MLOps 2026

MLOps course

Recommender runtime and trainingRecommender runtime and training

An MLOps course project with a factory-based FastAPI application named recommender, served by Uvicorn. App and router instances are created inside factories. RecommenderApplication owns the app and receives its service in the constructor; RecommendationRouter owns the versioned routes and service reference. The injected RecommendationService implements __aenter__ and __aexit__ for model loading and deterministic shutdown. Its idempotent close() also runs from __del__ as a fallback. Application, router and service state is private; app and router access use explicit read-only properties. Imports do not start services or create shared application instances. Response contracts are exported from internal/models. Implementation lives under internal/recommender/, with other future apps owning sibling packages under internal/ and separate cmd/ entry points.

bazel_agent bazel run //projects/mlops_2026/cmd/recommender -- --host 127.0.0.1 --port 8000

The defaults are 127.0.0.1:8000. GET /health returns {"status": "ok"}. FastAPI serves the generated schema at /openapi.json, Swagger UI at /docs, and ReDoc at /redoc; the documentation UIs use FastAPI’s default external assets. GET /api/v1/recommend?track_name=Time&n=5 returns requested_track and song recommendations containing track_name, artists, and album_name. track_name is required; n defaults to 5 and must be between 1 and 20. An unknown track returns an empty list. Invalid queries return HTTP 422.

The pinned upstream data.csv and dataset.csv are included in the executable runfiles and resolved independently of the working directory. Startup checks that both exist. Each app loads its packaged model once during startup using the upstream load_model function, then releases it on shutdown. Health checks do not invoke recommendation computation. Source and integrity are owned by third_party/com_github_yandex_practicum_mlops_freetrack/.

bazel_agent bazel build //projects/mlops_2026:model

The sandboxed target runs the upstream train_and_save_model.py unchanged, stages its CSV inputs in an action directory, and produces bazel-bin/projects/mlops_2026/model.pkl. It exposes a declared build artifact consumed by the recommender executable. The upstream script is also buildable as //third_party/com_github_yandex_practicum_mlops_freetrack:train_and_save_model; running that script directly requires a working directory with both CSVs and writes model.pkl there. Prefer the model build target for isolated execution.

The full training data joins to 6,788 unique tracks. Its dense similarity matrix uses about 0.34 GiB; the serialized artifact is about 359 MiB. The model target and isolated model verification are marked manual, but building or testing the recommender now requires this artifact and can trigger training when it is not cached. Shared Python dependencies are declared and locked under tools/py/.

bazel_agent bazel test //projects/mlops_2026/test/e2e:recommender_test
bazel_agent bazel test //projects/mlops_2026/test/e2e:model_test

These checks exercise real HTTP, factory isolation, startup conflict handling, shutdown, service context exit, repeated and deletion cleanup, course runfiles and checksums, and a recommendation from the built model. Repeatable JSON artifacts are saved in each test’s undeclared outputs under bazel-testlogs/projects/mlops_2026/test/e2e/. There is no deployment or release target.

1 - OpenSpec

1.1 - Specifications

1.1.1 - Course data

1.1.1.1 - course-data Specification

Make the two upstream course datasets available to the MLOps application at runtime with reproducible source identity and no checkout-path dependency.

The application runtime bundle SHALL include data.csv and dataset.csv from an immutable, integrity-verified revision of the user-requested Yandex-Practicum/mlops-freetrack repository. Both files SHALL be available through application runfiles without network downloads or dependence on the repository working directory. Their bytes SHALL match the pinned upstream files.

  • WHEN the Bazel-built application is launched from a different directory
  • THEN both CSV files resolve through its runfiles and can be opened
  • AND their checksums match the pinned upstream source
  • WHEN the server starts with both course CSV files in its runtime bundle
  • THEN GET /health retains its agreed response without parsing the datasets or invoking recommendation computation

The repository SHALL expose a runnable upstream training target and a Bazel build target whose declared output is model.pkl. Training SHALL use the pinned course CSV files and resolved upstream Python dependencies without network access or writing into source directories. The artifact SHALL be usable by a future model consumer; the recommendation server SHALL load it through the upstream loader.

  • WHEN the model build target is selected
  • THEN it runs the pinned upstream training code against the pinned datasets and produces a nonempty model.pkl in the Bazel output tree
  • AND a verification consumer loads it and obtains a structurally valid recommendation from a track present in the model

1.1.2 - Course placeholder

1.1.2.1 - course-placeholder Specification

Describe current MLOps course documentation and supported local commands.

The project SHALL provide a README identifying it as an MLOps course and linking the user-supplied course page. After implementation it SHALL describe the runnable health service and its supported endpoints and startup command, rather than claiming that no code exists. Its documentation SHALL remain included through repository documentation targets. The local application SHALL NOT require a release deployment target.

  • WHEN a reader opens the project README after implementation
  • THEN its description and external link identify the course
  • AND it documents the health service, OpenAPI endpoints, and local startup
  • WHEN repository consumers select the project documentation
  • THEN its README and baseline specification are included
  • AND release aggregation does not require an absent course release target

1.1.3 - Health api

1.1.3.1 - health-api Specification

Provide a runnable HTTP foundation for the MLOps course with a health check, an inspectable API description, and independent application instances.

The service SHALL respond to GET /health with HTTP 200 and the JSON object {“status”: “ok”}. The response SHALL indicate that the HTTP application is running without invoking recommendation computation or external services.

  • WHEN a client sends GET /health to a running service
  • THEN it receives HTTP 200 with application/json content and {“status”: “ok”}

The service SHALL provide a valid OpenAPI document at GET /openapi.json, including the health endpoint and its successful response contract. It SHALL provide the default documentation pages at /docs and /redoc, configured to use that schema URL.

  • WHEN a client requests GET /openapi.json
  • THEN it receives HTTP 200 with a valid OpenAPI JSON document describing GET /health and its successful JSON response
  • WHEN a client requests GET /docs or GET /redoc
  • THEN it receives HTTP 200 with an HTML documentation page referring to /openapi.json

Future application endpoints SHALL use /api/v1 as their initial routing prefix. Recommendations SHALL be exposed under that prefix; health and default API documentation SHALL retain their agreed root paths.

  • WHEN a client requests GET /api/v1/predict
  • THEN the service responds with HTTP 404 rather than exposing prediction or placeholder business behavior

Constructing an application SHALL create fresh application and routing state. Importing application modules SHALL NOT start a server, create shared mutable application instances, or allocate external service resources. Changes to one application’s routing SHALL NOT affect another application’s routing.

  • WHEN two applications are constructed in one process and routing is subsequently added to one of them
  • THEN the other application’s routes remain unchanged

Requirement: Provide a configurable local server entry point

The service SHALL be runnable through a repository Bazel target with configurable host and port. It SHALL bind to 127.0.0.1:8000 by default, accept an explicitly selected loopback address and available port, and shut down cleanly on termination.

  • WHEN the server target starts with a loopback host and an available port
  • THEN the health and OpenAPI endpoints are served on that address
  • AND terminating the server releases its resources and listening socket

GET /api/v1/recommend SHALL accept a required track_name query and an integer n query defaulting to 5, constrained to 1 through 20. It SHALL return a RecommenderRecommendationResponse with requested_track and recommendations of RecommenderSong (track_name, artists, album_name). It SHALL use the upstream load_model function to load the declared model.pkl during application lifespan, with per-application state and no global model object.

  • WHEN a client requests a track in the trained model with n=3
  • THEN it receives HTTP 200 and three typed song recommendations
  • AND requested_track matches the query
  • WHEN n is 0, 21, or nonnumeric, or track_name is absent
  • THEN the response is HTTP 422
  • WHEN track_name does not exist in the model
  • THEN requested_track is preserved and recommendations is empty