feat(#167): Implement Runner jobs CRUD and queue submission
Implements runner-jobs module for job lifecycle management and queue submission. Changes: - Created RunnerJobsModule with service, controller, and DTOs - Implemented job creation with BullMQ queue submission - Implemented job listing with filters (status, type, agentTaskId) - Implemented job detail retrieval with steps and events - Implemented cancel operation for pending/queued jobs - Implemented retry operation for failed jobs - Added comprehensive unit tests (24 tests, 100% coverage) - Integrated with BullMQ for async job processing - Integrated with Prisma for database operations - Followed existing CRUD patterns from tasks/events modules API Endpoints: - POST /runner-jobs - Create and queue a new job - GET /runner-jobs - List jobs (with filters) - GET /runner-jobs/:id - Get job details - POST /runner-jobs/:id/cancel - Cancel a running job - POST /runner-jobs/:id/retry - Retry a failed job Quality Gates: - Typecheck: ✅ PASSED - Lint: ✅ PASSED - Build: ✅ PASSED - Tests: ✅ PASSED (24/24 tests) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
90
apps/api/src/runner-jobs/runner-jobs.controller.ts
Normal file
90
apps/api/src/runner-jobs/runner-jobs.controller.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { Controller, Get, Post, Body, Param, Query, UseGuards } from "@nestjs/common";
|
||||
import { RunnerJobsService } from "./runner-jobs.service";
|
||||
import { CreateJobDto, QueryJobsDto } from "./dto";
|
||||
import { AuthGuard } from "../auth/guards/auth.guard";
|
||||
import { WorkspaceGuard, PermissionGuard } from "../common/guards";
|
||||
import { Workspace, Permission, RequirePermission } from "../common/decorators";
|
||||
import { CurrentUser } from "../auth/decorators/current-user.decorator";
|
||||
import type { AuthenticatedUser } from "../common/types/user.types";
|
||||
|
||||
/**
|
||||
* Controller for runner job endpoints
|
||||
* All endpoints require authentication and workspace context
|
||||
*
|
||||
* Guards are applied in order:
|
||||
* 1. AuthGuard - Verifies user authentication
|
||||
* 2. WorkspaceGuard - Validates workspace access and sets RLS context
|
||||
* 3. PermissionGuard - Checks role-based permissions
|
||||
*/
|
||||
@Controller("runner-jobs")
|
||||
@UseGuards(AuthGuard, WorkspaceGuard, PermissionGuard)
|
||||
export class RunnerJobsController {
|
||||
constructor(private readonly runnerJobsService: RunnerJobsService) {}
|
||||
|
||||
/**
|
||||
* POST /api/runner-jobs
|
||||
* Create a new runner job and queue it
|
||||
* Requires: MEMBER role or higher
|
||||
*/
|
||||
@Post()
|
||||
@RequirePermission(Permission.WORKSPACE_MEMBER)
|
||||
async create(
|
||||
@Body() createJobDto: CreateJobDto,
|
||||
@Workspace() workspaceId: string,
|
||||
@CurrentUser() _user: AuthenticatedUser
|
||||
) {
|
||||
return this.runnerJobsService.create(workspaceId, createJobDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/runner-jobs
|
||||
* Get paginated jobs with optional filters
|
||||
* Requires: Any workspace member (including GUEST)
|
||||
*/
|
||||
@Get()
|
||||
@RequirePermission(Permission.WORKSPACE_ANY)
|
||||
async findAll(@Query() query: QueryJobsDto, @Workspace() workspaceId: string) {
|
||||
return this.runnerJobsService.findAll(Object.assign({}, query, { workspaceId }));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/runner-jobs/:id
|
||||
* Get a single job by ID
|
||||
* Requires: Any workspace member
|
||||
*/
|
||||
@Get(":id")
|
||||
@RequirePermission(Permission.WORKSPACE_ANY)
|
||||
async findOne(@Param("id") id: string, @Workspace() workspaceId: string) {
|
||||
return this.runnerJobsService.findOne(id, workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/runner-jobs/:id/cancel
|
||||
* Cancel a running or queued job
|
||||
* Requires: MEMBER role or higher
|
||||
*/
|
||||
@Post(":id/cancel")
|
||||
@RequirePermission(Permission.WORKSPACE_MEMBER)
|
||||
async cancel(
|
||||
@Param("id") id: string,
|
||||
@Workspace() workspaceId: string,
|
||||
@CurrentUser() _user: AuthenticatedUser
|
||||
) {
|
||||
return this.runnerJobsService.cancel(id, workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/runner-jobs/:id/retry
|
||||
* Retry a failed job
|
||||
* Requires: MEMBER role or higher
|
||||
*/
|
||||
@Post(":id/retry")
|
||||
@RequirePermission(Permission.WORKSPACE_MEMBER)
|
||||
async retry(
|
||||
@Param("id") id: string,
|
||||
@Workspace() workspaceId: string,
|
||||
@CurrentUser() _user: AuthenticatedUser
|
||||
) {
|
||||
return this.runnerJobsService.retry(id, workspaceId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user