# Job Status Service Plan ## Objective Create a separate reusable library/service that accepts only a job name and returns: - current `status` - parsed `response` The service should use `JobModel` (`jobs` table) and align with existing queue statuses used in `JobWorker` (`queued`, `running`, `done`, `failed`). ## Current Context - `JobWorker` writes job execution data into `jobs`: - updates `status` - updates `run_time` - writes JSON-encoded `response` - `JobModel` is a basic model mapped to `jobs` table with relevant fields already allowed. ## Proposed Design 1. Create a dedicated library class: - Path: `app/Libraries/JobStatusService.php` - Responsibility: read latest job record by `name`, normalize output payload. 2. Public API of library: - Method: `getJobStatusByName(string $jobName): array` - Input: job name only - Output contract (example): - `success` (bool) - `job_name` (string) - `status` (string|null) - `response` (array|string|null) - `job_id` (int|null) - `uuid` (string|null) - `run_time` (float|int|null) - `message` (string) 3. Query behavior: - Search in `jobs` table by exact `name = $jobName` - Order by latest execution (`id DESC`) and fetch first row - If no record exists, return `success=false` with clear message. 4. Response normalization: - Attempt `json_decode(response, true)` when response is non-empty. - If decode succeeds, return decoded array/object structure. - If decode fails or is plain text, return raw response string. - Keep response key consistent regardless of format. 5. Validation and safety: - Trim input name and reject empty values. - Avoid exceptions leaking to caller; wrap unexpected errors and return structured failure response. ## Integration Plan 1. Keep the library independent from controllers for reuse. 2. Optional usage points: - API controller endpoint can consume the library and return JSON to frontend. - CLI/debug scripts can consume the same library. 3. No changes required in `JobWorker` queue execution flow for this feature. ## Suggested Controller Endpoint (Optional Next Step) If needed after library creation: - Add endpoint method (example in `ApiServiceController`) accepting `job_name`. - Validate `job_name`. - Call `JobStatusService::getJobStatusByName($jobName)`. - Return JSON response with appropriate HTTP code: - 200 for found - 404 for not found - 422 for invalid input - 500 for unexpected server errors ## Edge Cases - Multiple jobs with same name: return latest record only. - `queued`/`running` jobs may have empty response; return `response=null`. - Failed jobs may contain JSON error bundle written by `JobWorker`; return decoded details when valid JSON. - Done jobs may return scalar/string payload; preserve as-is when not JSON. ## Testing Plan 1. Unit-level checks for service method: - Valid job name with `done` status and JSON response - Valid job name with `failed` status and JSON error response - Valid job name with non-JSON response - Valid job name not found - Empty job name input 2. Integration checks (optional): - Trigger known queue job, then fetch status by name and verify status/response shape. ## Deliverables 1. `app/Libraries/JobStatusService.php` with `getJobStatusByName()` method. 2. (Optional) Controller method + route for API access. 3. Minimal usage example in developer notes or inline docblock. ## Implementation Steps (Execution Order) 1. Create `app/Libraries/JobStatusService.php`. 2. Add constructor or internal setup to initialize `JobModel`. 3. Implement input guard: - trim `$jobName` - return failure payload for empty input. 4. Fetch latest row by `name`: - `where('name', $jobName)->orderBy('id', 'DESC')->first()` 5. Build normalized response payload: - `status`, `job_id`, `uuid`, `run_time`, `response`. 6. Decode response safely: - if empty -> `null` - if valid JSON -> decoded array/object - else -> raw string. 7. Add broad `try/catch (\Throwable $e)` and return safe error contract. 8. (Optional) Wire endpoint in `ApiServiceController` and route mapping. 9. Verify manually with one known queued/running job and one completed/failed job. ## Payload Contract (Final) ```php [ 'success' => true|false, 'job_name' => (string), 'status' => (string|null), // queued|running|done|failed|null 'response' => (array|string|null), 'job_id' => (int|null), 'uuid' => (string|null), 'run_time' => (float|int|null), 'message' => (string), ] ``` ## Error Handling Rules - Invalid input (`job_name` empty after trim): - `success=false`, `message='Job name is required.'` - Not found: - `success=false`, `message='No job record found for given name.'` - Unexpected exception: - `success=false`, `message='Unable to fetch job status right now.'` - keep internals/logging server-side only, do not leak stack trace in API response. ## Optional Route/Endpoint Mapping If API exposure is required, prefer a read-only endpoint: - `GET /api/job-status?job_name={name}` or - `POST /api/job-status` with body `{ "job_name": "..." }` Response guidance: - 200: `success=true` - 404: not found - 422: validation failure - 500: unexpected server failure ## Acceptance Criteria - Given an existing job `name`, service returns latest row by descending `id`. - `status` always reflects one of existing worker statuses or `null`. - `response` is decoded when valid JSON; otherwise preserved as raw string. - Empty input never triggers DB query and returns validation failure. - Service never throws unhandled exception to caller. ## Non-Goals (Current Scope) - No change to existing queue insert/update logic in `JobWorker`. - No migration/schema change in `jobs` table. - No polling/real-time websocket updates in this phase. ## Rollout Notes 1. Implement service first and test in isolation. 2. Add endpoint only if a frontend or external consumer needs it immediately. 3. Keep endpoint backward-compatible by not changing existing job payload fields. 4. Add lightweight log entry only for unexpected exceptions to aid debugging. ## Completed Tasks (Updated) - [x] Created `app/Libraries/JobStatusService.php`. - [x] Added `getJobStatusByName(string $jobName): array`. - [x] Implemented empty input validation with structured failure response. - [x] Implemented latest-record lookup by exact `name` and `id DESC`. - [x] Implemented response normalization (`null` / decoded JSON / raw string). - [x] Added safe exception handling and server-side error logging. - [x] Added API endpoint method `ApiServiceController::jobStatus`. - [x] Added routes: - `GET /jobStatus` - `POST /jobStatus` - [ ] Manual verification against queued/running/done/failed sample jobs (pending). ## Route Migration Plan (ApiServiceController -> TestingController) ### Objective Move the `jobStatus` endpoint ownership from `ApiServiceController` to `TestingController` while keeping URL contract unchanged. ### Steps 1. Add `JobStatusService` import in `TestingController`. 2. Add `jobStatus()` method in `TestingController` with the same input/output behavior. 3. Remove `jobStatus()` method from `ApiServiceController` to avoid duplicate ownership. 4. Update route mapping in `Routes.php`: - `GET /jobStatus -> TestingController::jobStatus` - `POST /jobStatus -> TestingController::jobStatus` 5. Run syntax checks for updated controller and routes. ### Migration Tasks (Updated) - [x] Added `use App\Libraries\JobStatusService;` in `TestingController`. - [x] Added `TestingController::jobStatus()` (GET/POST + JSON fallback). - [x] Removed `ApiServiceController::jobStatus()`. - [x] Repointed both `jobStatus` routes to `TestingController`. - [ ] Manual endpoint validation via GET and POST with sample `job_name` values (pending).