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