velocious-jobler
v0.0.2
Published
Track background-job progress and show it live in a React Native / Expo UI over Velocious frontend-model websockets — a jobler-style tracker for the Velocious stack.
Downloads
437
Maintainers
Readme
velocious-jobler
Track background-job progress and show it live in a React Native / Expo UI, driven by Velocious frontend-model websockets. A jobler-style tracker for the Velocious stack.
A background service creates a jobler job record, updates its status/progress as it runs, and — because the job is a broadcasting Velocious frontend-model resource — the Expo UI subscribes to it and renders progress as it happens. No polling.
Status:
0.0.1. Extracted from a working implementation in a real app; the runner and the UI component are framework-light and reusable. The Velocious model, model-base, frontend-model resource and migration are shipped by the package as a fully-generic (no-account) data layer — a consuming app registers the package and the framework auto-discovers them.
Install
npm install velocious-joblerPeer dependencies (frontend component only): react, react-native, prop-types, and set-state-compare (Velocious's ShapeComponent).
1. The jobler job data layer (shipped)
The package ships a fully-generic JoblerJob — model, model-base, read-only frontend-model resource and migration — with no account/owner coupling (no account_id, no belongsTo). It is a standalone background-job progress tracker: any authenticated user can find one by its unguessable uuid id, and there is no index/list command, so there is no cross-tenant listing leak. Only your backend services create and mutate jobs; clients just read + subscribe.
Columns (global DB — not a tenant DB):
| column | type | notes |
| --- | --- | --- |
| id | uuid | primary key |
| name | string | human label, e.g. "Deleting project Foo" |
| kind | string | e.g. "project_destroy" |
| status | string | pending | running | succeeded | failed |
| progress_current | integer | default 0 |
| progress_total | integer, null | null = indeterminate |
| status_message | string, null | current step |
| error_message | text, null | set on failure |
| result_data | text/json, null | optional |
| started_at / finished_at | datetime, null | |
| created_at / updated_at | datetime | timestamps |
Register the package in your Velocious app so the framework auto-discovers the model, resource and migration:
import joblerPackage from "velocious-jobler/velocious-package"
// In your Velocious Configuration:
new Configuration({
packages: [joblerPackage]
// ...your other config
})Then generate its frontend model and run the migration:
velocious generate:frontend-models
velocious db:migrateBecause the resource is a broadcasting read-only frontend-model resource, its create/update/destroy events flow over the websocket to subscribed clients.
2. Backend: run work with live progress
import JoblerJobRunner from "velocious-jobler/backend/jobler-job-runner"
await new JoblerJobRunner({
// optional: route failures to your bug reporter
onError: (error, joblerJob) => bugReporter.reportError({error, parameters: {joblerJobId: joblerJob.id()}})
}).run({
joblerJob,
work: async (report) => {
await report.progress({current: 0, total: 3, message: "Dropping database"})
await dropDatabase()
await report.progress({current: 1, total: 3, message: "Cleaning up"})
await cleanup()
await report.progress({current: 2, total: 3, message: "Finishing"})
await finish()
}
})run(...) marks the job running, saves each report.progress(...)/report.message(...) update (each save() is a websocket push), then marks it succeeded — or, on a throw, marks it failed, calls onError, and rethrows so your background-job retry policy still applies. Dispatch it from a normal Velocious background job.
3. Frontend: show it in Expo
import JobProgressIndicator from "velocious-jobler/frontend/job-progress-indicator"
import JoblerJob from "@/src/frontend-models/jobler-job.js"
<JobProgressIndicator
model={JoblerJob}
joblerJobId={joblerJobId}
onSucceeded={() => router.replace("/somewhere")}
onFailed={({errorMessage}) => FlashNotifications.error(errorMessage)}
/>It loads the job through model.findBy({id}), subscribes with model.onUpdate(...), renders status + a progress bar + the message, and fires onSucceeded / onFailed once when the job reaches a terminal status. Override the built-in English labels via the labels prop ({loading, working, failed}).
License
MIT © Kasper Stöckel
