Querying
Scheduled queries
Running queries on a schedule
Orbital supports running saved queries automatically on a schedule. This is useful for scenarios such as:
- Polling an external API every few minutes
- Refreshing a dataset at a regular interval
- Running nightly sync or cleanup jobs
Scheduled queries complement existing HTTP Endpoints and Background Streams, giving you multiple ways to publish and reuse queries.
Defining a Scheduled Query
You declare a scheduled query using the @Scheduled annotation:
import com.orbitalhq.scheduler.Scheduled
@Scheduled(cron = "0 0/5 * * * ?")query RefreshProducts { find { Product[] }}Be sure to include the import statement: import com.orbitalhq.scheduler.Scheduled
This runs the query RefreshProducts every 5 minutes.
Under the hood, Orbital uses Quartz Scheduler with a JDBC-backed job store, so schedules are persistent and cluster-safe.
Annotation Reference
namespace com.orbitalhq.scheduler
annotation Scheduled { /** * Cron expression (Quartz format) */ cron: String?
/** * Run with fixed rate (ISO-8601 duration or shorthand like "10m") */ fixedRate: String?
/** * Max number of executions (-1 = forever) */ repeatCount: Int = -1
/** * What to do if a fire is missed */ misfirePolicy: MisfirePolicy = MisfirePolicy.Default
/** * Trigger priority (higher runs first) */ priority: Int = 5}
enum MisfirePolicy { Default, FireImmediately, Skip}| Property | Description | Example / Values | Default |
|---|---|---|---|
| cron | A Quartz cron expression with 6 fields: seconds, minutes, hours, day-of-month, month, day-of-week. | 0 0 2 * * ? → 2:00 AM daily | None (required if fixedRate not set) |
| fixedRate | Run at a fixed interval. Supports ISO-8601 durations or shorthand. | PT10M or 10m | None (required if cron not set) |
| repeatCount | Number of times to run. | -1 = forever | -1 |
| misfirePolicy | How to handle missed runs. | Default (Quartz’s smart policy, usually fire once now)FireImmediately (catch up immediately)Skip (ignore missed runs, wait for next) | Default |
| priority | Trigger priority if multiple jobs fire simultaneously. | 5 (default), higher numbers run first | 5 |
Supported Query Types
Scheduled queries must be finite queries (find or call).
Streaming queries (stream { }) cannot be scheduled.
Admin & Monitoring
Scheduled queries are listed on the Endpoints page in the Orbital UI, alongside the queries published as HTTP endpoints, with a type of Scheduled query:
Each scheduled run is recorded on the Activity page, where you can open it to see its results, the services it called and how long it took - see Query lineage and observability. Results are kept according to the workspace’s query history settings.
Cluster Behavior
When running in a cluster, job scheduling is co-ordinated across the cluster, using Quartz and the Postgres job store to coordinate execution.
At any given time, exactly one node will execute a scheduled query, ensuring there are no duplicates. If a node crashes or becomes unavailable, another node in the cluster automatically takes over future runs.
Examples
Hourly polling job:
import com.orbitalhq.scheduler.Scheduled @Scheduled(fixedRate = "1h")query PollApi { call { ExternalApi[] }}Nightly batch job:
@Scheduled(cron = "0 0 2 * * ?", misfirePolicy = FireImmediately)query NightlySync { find { Orders }}Limitations
- No support yet for multiple schedules per query (one
@Scheduledper query). - Missed runs are not replayed unless
misfirePolicyis set.