update api, fix tests and examples
This commit is contained in:
333
docs/job-api-convention.md
Normal file
333
docs/job-api-convention.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# Hero Supervisor Job API Convention
|
||||
|
||||
## Overview
|
||||
|
||||
The Hero Supervisor OpenRPC API follows a consistent naming convention for job-related operations:
|
||||
|
||||
- **`jobs.`** - General job operations (plural)
|
||||
- **`job.`** - Specific job operations (singular)
|
||||
|
||||
This convention provides a clear distinction between operations that work with multiple jobs or create new jobs versus operations that work with a specific existing job.
|
||||
|
||||
## API Methods
|
||||
|
||||
### General Job Operations (`jobs.`)
|
||||
|
||||
#### `jobs.create`
|
||||
Creates a new job without immediately queuing it to a runner.
|
||||
|
||||
**Parameters:**
|
||||
- `secret` (string): Authentication secret (admin or user)
|
||||
- `job` (Job object): Complete job specification
|
||||
|
||||
**Returns:**
|
||||
- `job_id` (string): Unique identifier of the created job
|
||||
|
||||
**Usage:**
|
||||
```json
|
||||
{
|
||||
"method": "jobs.create",
|
||||
"params": {
|
||||
"secret": "your-secret",
|
||||
"job": {
|
||||
"id": "job-123",
|
||||
"caller_id": "client-1",
|
||||
"context_id": "context-1",
|
||||
"payload": "print('Hello World')",
|
||||
"executor": "osis",
|
||||
"runner": "osis-runner-1",
|
||||
"timeout": 300,
|
||||
"env_vars": {},
|
||||
"created_at": "2023-01-01T00:00:00Z",
|
||||
"updated_at": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `jobs.list`
|
||||
Lists all jobs in the system with full details.
|
||||
|
||||
**Parameters:** None
|
||||
|
||||
**Returns:**
|
||||
- `jobs` (array of Job objects): List of all jobs with complete information
|
||||
|
||||
**Usage:**
|
||||
```json
|
||||
{
|
||||
"method": "jobs.list",
|
||||
"params": []
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "job-123",
|
||||
"caller_id": "client-1",
|
||||
"context_id": "context-1",
|
||||
"payload": "print('Hello World')",
|
||||
"executor": "osis",
|
||||
"runner": "osis-runner-1",
|
||||
"timeout": 300,
|
||||
"env_vars": {},
|
||||
"created_at": "2023-01-01T00:00:00Z",
|
||||
"updated_at": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Specific Job Operations (`job.`)
|
||||
|
||||
#### `job.run`
|
||||
Runs a job immediately on the appropriate runner and returns the result.
|
||||
|
||||
**Parameters:**
|
||||
- `secret` (string): Authentication secret (admin or user)
|
||||
- `job` (Job object): Complete job specification
|
||||
|
||||
**Returns:**
|
||||
- `result` (JobResult): Either success or error result
|
||||
|
||||
**JobResult Format:**
|
||||
```json
|
||||
// Success case
|
||||
{
|
||||
"success": "Job completed successfully with output..."
|
||||
}
|
||||
|
||||
// Error case
|
||||
{
|
||||
"error": "Job failed with error message..."
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```json
|
||||
{
|
||||
"method": "job.run",
|
||||
"params": {
|
||||
"secret": "your-secret",
|
||||
"job": { /* job object */ }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `job.start`
|
||||
Starts a previously created job by queuing it to its assigned runner.
|
||||
|
||||
**Parameters:**
|
||||
- `secret` (string): Authentication secret (admin or user)
|
||||
- `job_id` (string): ID of the job to start
|
||||
|
||||
**Returns:** `null` (void)
|
||||
|
||||
**Usage:**
|
||||
```json
|
||||
{
|
||||
"method": "job.start",
|
||||
"params": {
|
||||
"secret": "your-secret",
|
||||
"job_id": "job-123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `job.status`
|
||||
Gets the current status of a job.
|
||||
|
||||
**Parameters:**
|
||||
- `job_id` (string): ID of the job to check
|
||||
|
||||
**Returns:**
|
||||
- `status` (JobStatusResponse): Current job status information
|
||||
|
||||
**JobStatusResponse Format:**
|
||||
```json
|
||||
{
|
||||
"job_id": "job-123",
|
||||
"status": "running",
|
||||
"created_at": "2023-01-01T00:00:00Z",
|
||||
"started_at": "2023-01-01T00:00:05Z",
|
||||
"completed_at": null
|
||||
}
|
||||
```
|
||||
|
||||
**Status Values:**
|
||||
- `created` - Job has been created but not queued
|
||||
- `queued` - Job has been queued to a runner
|
||||
- `running` - Job is currently executing
|
||||
- `completed` - Job finished successfully
|
||||
- `failed` - Job failed with an error
|
||||
- `timeout` - Job timed out
|
||||
|
||||
**Usage:**
|
||||
```json
|
||||
{
|
||||
"method": "job.status",
|
||||
"params": ["job-123"]
|
||||
}
|
||||
```
|
||||
|
||||
#### `job.result`
|
||||
Gets the result of a completed job. This method blocks until the result is available.
|
||||
|
||||
**Parameters:**
|
||||
- `job_id` (string): ID of the job to get results for
|
||||
|
||||
**Returns:**
|
||||
- `result` (JobResult): Either success or error result
|
||||
|
||||
**Usage:**
|
||||
```json
|
||||
{
|
||||
"method": "job.result",
|
||||
"params": ["job-123"]
|
||||
}
|
||||
```
|
||||
|
||||
#### `job.stop`
|
||||
Stops a running job.
|
||||
|
||||
**Parameters:**
|
||||
- `secret` (string): Authentication secret (admin or user)
|
||||
- `job_id` (string): ID of the job to stop
|
||||
|
||||
**Returns:** `null` (void)
|
||||
|
||||
**Usage:**
|
||||
```json
|
||||
{
|
||||
"method": "job.stop",
|
||||
"params": {
|
||||
"secret": "your-secret",
|
||||
"job_id": "job-123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `job.delete`
|
||||
Deletes a job from the system.
|
||||
|
||||
**Parameters:**
|
||||
- `secret` (string): Authentication secret (admin or user)
|
||||
- `job_id` (string): ID of the job to delete
|
||||
|
||||
**Returns:** `null` (void)
|
||||
|
||||
**Usage:**
|
||||
```json
|
||||
{
|
||||
"method": "job.delete",
|
||||
"params": {
|
||||
"secret": "your-secret",
|
||||
"job_id": "job-123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Workflow Examples
|
||||
|
||||
### Fire-and-Forget Job
|
||||
```javascript
|
||||
// Create and immediately run a job
|
||||
const result = await client.job_run(secret, jobSpec);
|
||||
if (result.success) {
|
||||
console.log("Job completed:", result.success);
|
||||
} else {
|
||||
console.error("Job failed:", result.error);
|
||||
}
|
||||
```
|
||||
|
||||
### Asynchronous Job Processing
|
||||
```javascript
|
||||
// 1. Create the job
|
||||
const jobId = await client.jobs_create(secret, jobSpec);
|
||||
|
||||
// 2. Start the job
|
||||
await client.job_start(secret, jobId);
|
||||
|
||||
// 3. Poll for completion (non-blocking)
|
||||
let status;
|
||||
do {
|
||||
status = await client.job_status(jobId);
|
||||
if (status.status === 'running') {
|
||||
await sleep(1000); // Wait 1 second
|
||||
}
|
||||
} while (status.status === 'running' || status.status === 'queued');
|
||||
|
||||
// 4. Get the result
|
||||
const result = await client.job_result(jobId);
|
||||
```
|
||||
|
||||
### Batch Job Management
|
||||
```javascript
|
||||
// Create multiple jobs
|
||||
const jobIds = [];
|
||||
for (const jobSpec of jobSpecs) {
|
||||
const jobId = await client.jobs_create(secret, jobSpec);
|
||||
jobIds.push(jobId);
|
||||
}
|
||||
|
||||
// Start all jobs
|
||||
for (const jobId of jobIds) {
|
||||
await client.job_start(secret, jobId);
|
||||
}
|
||||
|
||||
// Monitor progress
|
||||
const results = [];
|
||||
for (const jobId of jobIds) {
|
||||
const result = await client.job_result(jobId); // Blocks until complete
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
// Optional: Stop or delete jobs if needed
|
||||
for (const jobId of jobIds) {
|
||||
await client.job_stop(secret, jobId); // Stop running job
|
||||
await client.job_delete(secret, jobId); // Delete from system
|
||||
}
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
All job operations require authentication using one of the following secret types:
|
||||
|
||||
- **Admin secrets**: Full access to all operations
|
||||
- **User secrets**: Access to job operations (`jobs.create`, `job.run`, `job.start`)
|
||||
- **Register secrets**: Only access to runner registration
|
||||
|
||||
## Error Handling
|
||||
|
||||
All methods return standard JSON-RPC error responses for:
|
||||
|
||||
- **Authentication errors** (-32602): Invalid or missing secrets
|
||||
- **Job not found errors** (-32000): Job ID doesn't exist
|
||||
- **Internal errors** (-32603): Server-side processing errors
|
||||
|
||||
## Migration from Legacy API
|
||||
|
||||
### Old → New Method Names
|
||||
|
||||
| Legacy Method | New Method | Notes |
|
||||
|---------------|------------|-------|
|
||||
| `run_job` | `job.run` | Same functionality, new naming |
|
||||
| `list_jobs` | `jobs.list` | Same functionality, new naming |
|
||||
| `create_job` | `jobs.create` | Enhanced to not auto-queue |
|
||||
|
||||
### New Methods Added
|
||||
|
||||
- `job.start` - Start a created job
|
||||
- `job.stop` - Stop a running job
|
||||
- `job.delete` - Delete a job from the system
|
||||
- `job.status` - Get job status (non-blocking)
|
||||
- `job.result` - Get job result (blocking)
|
||||
|
||||
### API Changes
|
||||
|
||||
- **Job struct**: Replaced `job_type` field with `executor`
|
||||
- **jobs.list**: Now returns full Job objects instead of just job IDs
|
||||
- **Enhanced job lifecycle**: Added stop and delete operations
|
||||
|
||||
This provides much more granular control over job lifecycle management.
|
Reference in New Issue
Block a user