Job Definitions
Job Definitions are resources that wrap components to make them schedulable. They define what code should run when a job is executed.
What are Job Definitions?
A Job Definition is a simple resource that associates a unique ID with a component. It acts as a template for creating jobs:
Component (code) → Job Definition (wrapper) → Job (scheduled instance)Why Job Definitions?
Job Definitions provide a layer of indirection that enables:
- Reusability: One component can have multiple job definitions
- Organization: Group related scheduled tasks
- Permissions: Control who can schedule which components
- Statistics: Track performance by job definition
Structure
A Job Definition consists of just two fields:
jobDefinitionId- Unique identifier for the definitioncomponentId- Which component to execute
uri: /resources/job-definitions/nightly-order-processingspec: componentId: process-orders.hreactorComplete Example
Here’s how to create a scheduled background task:
-
Create a component with the logic to execute:
process-orders.hreactor import 'resources'param processingDate: textlet orders = query orders(orderNumber)filter $'createdAt >= {processingDate}'orderBy 'createdAt asc'from orders select order =>sendEmail {to = order.customer.emailsubject = 'Processing Update'body = { html = '<p>Your order is being processed</p>' }dynamic = { orderId = order.id }} -
Create a job definition that wraps the component:
uri: /resources/components/process-orders.hreactorspec:codeFile: process-orders.hreactor---uri: /resources/job-definitions/nightly-order-processingspec:componentId: process-orders.hreactor -
Deploy the manifest:
Terminal window h_ manage apply h_manifest.yaml -
Schedule a job using the definition:
POST /resources/jobs{"jobDefinitionId": "nightly-order-processing","parameters": {"processingDate": "2025-11-15T00:00:00Z"},"runAt": "2025-11-16T02:00:00Z"}
Now the component will run at 2 AM with the specified parameters.
One Component, Multiple Definitions
A single component can be wrapped by multiple job definitions for different purposes:
# Same component for different use casesuri: /resources/job-definitions/hourly-syncspec: componentId: data-sync.hreactor
---uri: /resources/job-definitions/daily-full-syncspec: componentId: data-sync.hreactor
---uri: /resources/job-definitions/manual-syncspec: componentId: data-sync.hreactorThis allows:
- Different scheduling patterns (hourly vs daily)
- Different monitoring/statistics tracking
- Different permission scopes
- Same underlying logic
Managing Job Definitions
Job definitions are managed via the /resources/job-definitions API:
- Create/Update:
PUT /resources/job-definitions/{definitionId} - Get:
GET /resources/job-definitions/{definitionId} - List:
GET /resources/job-definitions - Delete:
DELETE /resources/job-definitions/{definitionId}
See the API Reference for complete endpoint documentation.
Job Definition vs Job
Job Definition:
- Template/configuration
- Points to a component
- Permanent resource
- One per scheduled task type
Job:
- Scheduled instance
- References a job definition
- Temporary (deleted after retention period)
- Many instances per definition
Example:
- Job Definition:
nightly-order-processing(permanent) - Jobs: Individual executions (Nov 15 2AM, Nov 16 2AM, Nov 17 2AM, etc.)
Access Control
Managing job definitions requires permissions:
job-definitions:read # View job definitionsjob-definitions:write # Create, update, delete job definitionsScheduling jobs from a definition requires access to the underlying component - see Jobs documentation for details.
Statistics & Monitoring
Job statistics are tracked by jobDefinitionId, making it easy to monitor performance of specific scheduled tasks:
GET /resources/jobs/statistics?jobDefinitionId=nightly-order-processingThis allows you to track:
- Success/failure rates for this specific task
- Execution time trends
- Queue depth for this definition
See Jobs documentation for complete statistics information.
Recurring Jobs Pattern
Hantera doesn’t have built-in cron scheduling. Instead, components can schedule themselves to create recurring jobs using relative time scheduling.
How It Works
A component schedules the next run at the end of its execution:
// Do the worklet orders = query orders(orderNumber) filter 'status = pending'
let processResult = orders select order => processOrder(order)
// Schedule next run (24 hours from now)from { effect = 'scheduleJob' definition = 'nightly-order-processing' at = now addDays 1 parameters = {}}This creates a self-perpetuating chain: Job completes → Schedules next run → Next job executes → Schedules another run → …
Common Patterns
Hourly Processing
// At end of componentfrom { effect = 'scheduleJob' definition = 'hourly-sync' at = now addHours 1 parameters = {}}Daily Processing
// At end of componentfrom { effect = 'scheduleJob' definition = 'daily-report' at = now addDays 1 parameters = {}}Weekly Processing
// At end of componentfrom { effect = 'scheduleJob' definition = 'weekly-cleanup' at = now addDays 7 parameters = {}}Custom Intervals
// Every 30 minutesfrom { effect = 'scheduleJob' definition = 'frequent-sync' at = now addMinutes 30 parameters = {}}Starting the Recurring Chain
Create the first job manually via API or rule to start the chain:
POST /resources/jobs{ "jobDefinitionId": "nightly-order-processing", "parameters": {}, "runAt": "2025-11-16T02:00:00Z"}After this first execution, the job schedules itself automatically.
Stopping Recurring Jobs
To stop a recurring job chain, cancel the next pending job:
DELETE /resources/jobs/{jobId}When a job is cancelled, it never executes, so it never schedules the next job. The chain breaks automatically.
Alternative methods:
- Update the component to remove self-scheduling logic (permanent change)
- Delete the job definition (will fail any pending jobs)
Best Practices
Use Descriptive IDs
Choose clear job definition IDs that describe purpose and frequency:
- ✅
hourly-inventory-sync,daily-report-generation,weekly-cleanup - ❌
job1,sync,task
Use Separate Definitions for Different Purposes
Create separate job definitions when you need distinct monitoring or different use cases:
# Same component, different purposes/monitoringuri: /resources/job-definitions/sync-customersspec: componentId: sync.hreactor
---uri: /resources/job-definitions/sync-productsspec: componentId: sync.hreactorThis allows independent statistics tracking and clearer monitoring of each use case.
Check for Pending Jobs Before Deletion
Before deleting a job definition, verify no pending jobs exist:
GET /resources/jobs?jobDefinitionId=my-definition&status=pendingSee Also
- Components - Learn about creating components
- Jobs - Scheduling and monitoring job executions
- API Reference - Complete API documentation