Async Jobs

Server-based asynchronous job execution in TypeScript

Server-based job execution with persistence, webhooks, and streaming — ideal for production deployments.

Diagram

Client

Jobs API

Async Job

Result

Quick Start

  1. Simple Usage
    bash
    npm install praisonai-ts
    typescript
    import { recipe } from 'praisonai-ts';
    
    const job = await recipe.submitJob('my-recipe', {
      input: { query: 'What is AI?' },
      wait: true,
    });
    console.log(job.status);
  2. With Configuration
    typescript
    const job = await recipe.submitJob('my-recipe', {
      input: { query: 'What is AI?' },
      webhookUrl: 'https://example.com/webhook',
      timeoutSec: 3600,
    });

Basic Usage

Submitting a Job

typescript
import { recipe } from 'praisonai-ts';

// Submit recipe as async job
const job = await recipe.submitJob('my-recipe', {
  input: { query: 'What is AI?' },
  config: { maxTokens: 1000 },
  sessionId: 'session_123',
  timeoutSec: 3600,
  webhookUrl: 'https://example.com/webhook',
  idempotencyKey: 'unique-key-123',
  apiUrl: 'http://127.0.0.1:8005',
});

console.log(`Job ID: ${job.jobId}`);
console.log(`Status: ${job.status}`);

JobHandle Interface

typescript
interface JobHandle {
  jobId: string;
  recipeName: string;
  status: JobStatus;

  getStatus(): Promise<JobStatus>;
  getResult(): Promise<any>;
  cancel(): Promise<boolean>;
  wait(pollInterval?: number, timeout?: number): Promise<any>;
}

type JobStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled';

Waiting for Completion

typescript
// Submit and wait
const job = await recipe.submitJob('my-recipe', {
  input: 'test',
  wait: true,
});

// Or wait after submission
const job = await recipe.submitJob('my-recipe', { input: 'test' });
const result = await job.wait(5, 300); // poll every 5s, timeout 300s
console.log(`Result: ${result}`);

Using the Jobs API Client

typescript
import { JobsClient, JobSubmitRequest } from 'praisonai-ts';

const client = new JobsClient('http://127.0.0.1:8005');

// Submit job
const request: JobSubmitRequest = {
  prompt: 'Analyze this data',
  recipeName: 'data-analyzer',
  recipeConfig: { format: 'json' },
  timeout: 3600,
  webhookUrl: 'https://example.com/callback',
};

const job = await client.submit(request);
console.log(`Job ID: ${job.jobId}`);

// Get status
const status = await client.getStatus(job.jobId);

// Get result
const result = await client.getResult(job.jobId);

// Stream progress
for await (const event of client.stream(job.jobId)) {
  console.log(`Progress: ${event.progress}%`);
}

Webhooks

typescript
const job = await recipe.submitJob('my-recipe', {
  input: 'test',
  webhookUrl: 'https://example.com/webhook',
});

Webhook payload:

json
{
  "jobId": "run_abc123",
  "status": "succeeded",
  "result": {"output": "..."},
  "completedAt": "2024-01-15T10:30:00Z",
  "durationSeconds": 45.2
}

Idempotency

typescript
// Same key = same job (no duplicate)
const job1 = await recipe.submitJob('my-recipe', {
  idempotencyKey: 'order-123',
});
const job2 = await recipe.submitJob('my-recipe', {
  idempotencyKey: 'order-123',
});

console.log(job1.jobId === job2.jobId); // true

Configuration

TEMPLATE.yaml Runtime Block

yaml
runtime:
  job:
    enabled: true
    timeout_sec: 3600
    webhook_url: "${WEBHOOK_URL}"
    idempotency_scope: "session"

Error Handling

typescript
import { recipe, JobError } from 'praisonai-ts';

try {
  const job = await recipe.submitJob('my-recipe', { input: 'test' });
  const result = await job.wait(5, 60);

  if (result.status === 'failed') {
    console.error(`Job failed: ${result.error}`);
  }
} catch (error) {
  if (error instanceof JobError) {
    console.error(`Job error: ${error.message}`);
  }
}

Related