Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 0 additions & 89 deletions ARCHITECTURE.md

This file was deleted.

67 changes: 65 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,65 @@
# controller_microservice_v2
Source code of controller microservice that handles data to and from frontend and jupyter kernel gateway for evolutionary algorithms on click v2
# Controller Microservice V2

Source code of controller microservice that handles data to and from frontend and jupyter kernel gateway for evolutionary algorithms on click v2.

## Overview

This service acts as the central orchestrator for the platform, managing:
- [User Sessions & Authentication](https://github.com/Evolutionary-Algorithms-On-Click/auth_microservice)
- Jupyter Kernel Lifecycle (via `jupyter_gateway`)
- Database Interactions (CockroachDB)
- Inter-service communication (gRPC, HTTP)
- [LLM microservice ](https://github.com/Evolutionary-Algorithms-On-Click/evocv2_llm_microservice)
- [Volpe Integration service](https://github.com/Evolutionary-Algorithms-On-Click/volpe-integration)

## Prerequisites

- **Go**: 1.24.1 or higher
- **Docker**: For containerization and dependencies (CockroachDB, MinIO, )
- **Docker Compose**: For orchestration
- **Make**: For running standard commands
- **Lefthook**: For git hooks (optional but recommended)

## Getting Started

### 1. Environment Setup

1. Clone the repository.
2. Ensure you have the necessary environment variables set. Refer to `docker-compose.yaml` for required keys (e.g., `DATABASE_URL`, `JUPYTER_GATEWAY_URL`).
*Note: The project uses `godotenv` to load environment variables from a `.env` file in development.*

### 2. Running Dependencies

Start the supporting services (Database, Object Storage, Jupyter Gateway, etc.):

```bash
make docker-up
```

or

```bash
docker-compose up --build
```


This will spin up CockroachDB, MinIO, Jupyter Gateway, and Python Runner as defined in `docker-compose.yaml`.

### 3. Local Development

To run the controller service locally:

```bash
# Install tools and git hooks
make setup

# Build and run the application
make run
```

The service will start on port `8080` (default).

## API Documentation

- **HTTP API**: Versioned under `/api/v1/`. Defined in `routes/api.go`.
- **gRPC**: Defined in `proto/authenticate.proto`.
93 changes: 93 additions & 0 deletions controllers/problem_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package controllers
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"time"
Expand Down Expand Up @@ -212,3 +214,94 @@ func (c *ProblemController) DeleteProblemByIDHandler(w http.ResponseWriter, r *h
c.Logger.Info().Str("problemID", problemID).Msg("successfully deleted problem by ID")
w.WriteHeader(http.StatusNoContent)
}

// SubmitNotebookHandler handles POST /api/v1/submission/submit
func (c *ProblemController) SubmitNotebookHandler(w http.ResponseWriter, r *http.Request) {
c.Logger.Info().Msg("received request to submit notebook")

user, ok := r.Context().Value(middleware.UserContextKey).(*middleware.User)
if !ok {
c.Logger.Error().Msg("user not found in context for submission")
http.Error(w, "user not found in context", http.StatusUnauthorized)
return
}

type submitRequest struct {
NotebookID string `json:"notebook_id"`
Filename string `json:"filename"`
SessionID string `json:"session_id"`
}

var req submitRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
c.Logger.Error().Err(err).Msg("invalid request body for submission")
http.Error(w, "invalid request body", http.StatusBadRequest)
return
}

if req.NotebookID == "" || req.Filename == "" || req.SessionID == "" {
http.Error(w, "notebook_id, filename, and session_id are required", http.StatusBadRequest)
return
}

// We don't limit the context time here as submission might take time, or we rely on default timeouts
ctx := r.Context()

result, err := c.ProblemModule.SubmitNotebook(ctx, user.ID, req.NotebookID, req.SessionID, req.Filename)
if err != nil {
c.Logger.Error().Err(err).Msg("failed to submit notebook")
http.Error(w, fmt.Sprintf("failed to submit notebook: %v", err), http.StatusInternalServerError)
return
}

pkg.WriteJSONResponseWithLogger(w, http.StatusOK, result, &c.Logger)
}

// GetSubmissionResultsHandler handles GET /api/v1/submission/results/{problemId}
func (c *ProblemController) GetSubmissionResultsHandler(w http.ResponseWriter, r *http.Request) {
problemID := r.PathValue("problemId")
c.Logger.Info().Str("problemID", problemID).Msg("received request to get submission results")

ctx := r.Context()

// Connect to volpe and get the stream
stream, err := c.ProblemModule.GetSubmissionResults(ctx, problemID)
if err != nil {
c.Logger.Error().Err(err).Msg("failed to get results stream")
http.Error(w, fmt.Sprintf("failed to get results: %v", err), http.StatusInternalServerError)
return
}
defer stream.Close()

w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")

flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "streaming not supported", http.StatusInternalServerError)
return
}

buf := make([]byte, 1024)
for {
n, err := stream.Read(buf)
if n > 0 {
if _, wErr := w.Write(buf[:n]); wErr != nil {
c.Logger.Error().Err(wErr).Msg("failed to write to response")
break
}
flusher.Flush()
}
if err != nil {
if err != io.EOF {
if errors.Is(err, context.Canceled) {
c.Logger.Info().Msg("client disconnected from submission results stream")
} else {
c.Logger.Error().Err(err).Msg("error reading from volpe stream")
}
}
break
}
}
}
3 changes: 2 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ services:
CULL_INTERVAL_MINUTES: 10
IDLE_THRESHOLD_MINUTES: 30
AUTH_GRPC_ADDRESS: "auth:5001"
LLM_MICROSERVICE_URL: "http://host.docker.internal:8000"
LLM_MICROSERVICE_URL: "http://host.docker.internal:5004"
VOLPE_SERVICE_URL: "http://host.docker.internal:7070"
USER_DATA_DIR: "/mnt/user_data"
networks:
- evoc-net
Expand Down
Loading