@kedem/okdb 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +57 -0
- package/README.md +344 -0
- package/banner.jpg +0 -0
- package/bin/okdb.js +2 -0
- package/docs/OKDB-ARCHITECTURE.md +1036 -0
- package/docs/auth-and-sync.md +558 -0
- package/docs/auth-permissions.md +143 -0
- package/docs/change-log.md +169 -0
- package/docs/data-model.md +174 -0
- package/docs/embeddings.md +338 -0
- package/docs/files.md +131 -0
- package/docs/fts.md +139 -0
- package/docs/functions.md +514 -0
- package/docs/getting-started.md +233 -0
- package/docs/http-api.md +705 -0
- package/docs/index.md +115 -0
- package/docs/indexes.md +207 -0
- package/docs/logging.md +116 -0
- package/docs/manifest.json +38 -0
- package/docs/migration.md +154 -0
- package/docs/pipelines.md +598 -0
- package/docs/plugins.md +144 -0
- package/docs/querying.md +204 -0
- package/docs/queue.md +637 -0
- package/docs/sync.md +156 -0
- package/docs/transactions.md +140 -0
- package/docs/ttl.md +375 -0
- package/okdb.js +1 -0
- package/package.json +26 -0
- package/public/admin-app.js +1 -0
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/components/admin-route-host.ok.js +1 -0
- package/public/components/env-picker.ok.js +1 -0
- package/public/components/field-path-input.ok.js +1 -0
- package/public/components/field.html +6 -0
- package/public/components/geo-map.ok.js +1 -0
- package/public/components/ok-cron-input.ok.js +1 -0
- package/public/components/ok-dropzone.ok.js +1 -0
- package/public/components/ok-js-input.ok.js +1 -0
- package/public/components/ok-json-input.ok.js +1 -0
- package/public/components/ok-text-monaco-input.ok.js +1 -0
- package/public/components/theme-toggle.ok.js +1 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/images/logo.png +0 -0
- package/public/images/logo.svg +333 -0
- package/public/index.html +6 -0
- package/public/layouts/_default.ok.html +1 -0
- package/public/layouts/okdb-cube.ok.html +1 -0
- package/public/login-app.js +1 -0
- package/public/login.html +1 -0
- package/public/modules/ok.js +1 -0
- package/public/sections/api/index.ok.html +1 -0
- package/public/sections/api/parts/api-endpoint.ok.js +1 -0
- package/public/sections/auth/index.ok.html +1 -0
- package/public/sections/auth/modals/create-token-modal.ok.js +1 -0
- package/public/sections/auth/modals/edit-token-modal.ok.js +1 -0
- package/public/sections/auth/modals/perm-info-popover.ok.js +1 -0
- package/public/sections/auth/parts/token-detail.ok.js +1 -0
- package/public/sections/auth/parts/token-list.ok.js +1 -0
- package/public/sections/db/index.ok.html +1 -0
- package/public/sections/db/modals/add-item-modal.ok.js +1 -0
- package/public/sections/db/modals/create-env-modal.ok.js +1 -0
- package/public/sections/db/modals/create-fts-modal.ok.js +1 -0
- package/public/sections/db/modals/create-index-modal.ok.js +1 -0
- package/public/sections/db/modals/create-pipeline-modal.ok.js +1 -0
- package/public/sections/db/modals/demo-env-modal.ok.js +1 -0
- package/public/sections/db/modals/remove-env-modal.ok.js +1 -0
- package/public/sections/db/modals/schema-edit-modal.ok.js +1 -0
- package/public/sections/db/parts/db-overview.ok.js +1 -0
- package/public/sections/db/parts/db-pipelines-panel.ok.js +1 -0
- package/public/sections/db/parts/edit-row.ok.js +1 -0
- package/public/sections/db/parts/tm-timeline.ok.js +1 -0
- package/public/sections/db/parts/type-changelog.ok.js +1 -0
- package/public/sections/db/parts/type-list.ok.js +1 -0
- package/public/sections/db/parts/type-pipelines-tab.ok.js +1 -0
- package/public/sections/db/parts/type-schema-tab.ok.js +1 -0
- package/public/sections/db/parts/type-viewer.ok.js +1 -0
- package/public/sections/db/parts/type-violations-tab.ok.js +1 -0
- package/public/sections/docs/index.ok.html +1 -0
- package/public/sections/embeddings/index.ok.html +1 -0
- package/public/sections/embeddings/modals/register-model-modal.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-create-panel.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-embedder-panel.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-engine-declaration-editor.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-engine-list.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-indexer-panel.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-lifecycle-bar.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-model-catalog.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-overview.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-search-panel.ok.js +1 -0
- package/public/sections/embeddings/parts/embed-worker-panel.ok.js +1 -0
- package/public/sections/embeddings/parts/embeddings-engine-panel.ok.js +1 -0
- package/public/sections/embeddings/parts/engines-overview.ok.js +1 -0
- package/public/sections/embeddings/parts/pipeline-create-panel.ok.js +1 -0
- package/public/sections/engines/engine-panel-shared-style.js +1 -0
- package/public/sections/engines/engine-ui-utils.js +1 -0
- package/public/sections/engines/index.ok.html +1 -0
- package/public/sections/engines/modals/engine-modal.ok.js +1 -0
- package/public/sections/engines/parts/engine-declaration-editor.ok.js +1 -0
- package/public/sections/engines/parts/engine-lifecycle-actions.ok.js +1 -0
- package/public/sections/engines/parts/engine-panel-shell.ok.js +1 -0
- package/public/sections/engines/parts/engine-resource-card.ok.js +1 -0
- package/public/sections/engines/parts/engine-row-item.ok.js +1 -0
- package/public/sections/engines/parts/generic-engine-panel.ok.js +1 -0
- package/public/sections/files/index.ok.html +1 -0
- package/public/sections/files/parts/files-blob-status.ok.js +1 -0
- package/public/sections/files/parts/files-collection-list.ok.js +1 -0
- package/public/sections/files/parts/files-collection-panel.ok.js +1 -0
- package/public/sections/files/parts/files-file-list.ok.js +1 -0
- package/public/sections/files/parts/files-overview.ok.js +1 -0
- package/public/sections/files/parts/files-path-browser.ok.js +1 -0
- package/public/sections/files/parts/files-upload-panel.ok.js +1 -0
- package/public/sections/functions/index.ok.html +1 -0
- package/public/sections/functions/modals/function-modal.ok.js +1 -0
- package/public/sections/functions/parts/function-detail.ok.js +1 -0
- package/public/sections/functions/parts/function-logs.ok.js +1 -0
- package/public/sections/functions/parts/function-runner.ok.js +1 -0
- package/public/sections/functions/parts/functions-list.ok.js +1 -0
- package/public/sections/license/index.ok.html +1 -0
- package/public/sections/license/parts/license-panel.ok.js +1 -0
- package/public/sections/processors/index.ok.html +1 -0
- package/public/sections/queue/index.ok.html +1 -0
- package/public/sections/queue/modals/create-bucket-modal.ok.js +1 -0
- package/public/sections/queue/modals/edit-bucket-modal.ok.js +1 -0
- package/public/sections/queue/modals/edit-job-modal.ok.js +1 -0
- package/public/sections/queue/modals/enqueue-job-modal.ok.js +1 -0
- package/public/sections/queue/modals/job-type-modal.ok.js +1 -0
- package/public/sections/queue/parts/ok-job-form.ok.js +1 -0
- package/public/sections/queue/parts/queue-buckets.ok.js +1 -0
- package/public/sections/queue/parts/queue-job-types.ok.js +1 -0
- package/public/sections/queue/parts/queue-jobs.ok.js +1 -0
- package/public/sections/queue/parts/queue-types.ok.js +1 -0
- package/public/sections/queue/parts/queue-workers.ok.js +1 -0
- package/public/sections/sync/index.ok.html +5 -0
- package/public/sections/sync/parts/sync-node-detail.ok.js +1 -0
- package/public/sections/sync/parts/sync-retention.ok.js +1 -0
- package/public/sections/sync/parts/sync-topology.ok.js +1 -0
- package/public/sections/system/index.ok.html +1 -0
- package/public/sections/system/modals/data-ops-modal.ok.js +1 -0
- package/public/sections/system/parts/system-api-panel.ok.js +1 -0
- package/public/sections/system/parts/system-auth-panel.ok.js +1 -0
- package/public/sections/system/parts/system-log-history.ok.js +1 -0
- package/public/sections/system/parts/system-log.ok.js +1 -0
- package/public/sections/system/parts/system-status.ok.js +1 -0
- package/public/sections/system/parts/system-sync-panel.ok.js +1 -0
- package/public/sections/views/index.ok.html +1 -0
- package/public/sections/views/modals/create-view-modal.ok.js +1 -0
- package/public/sections/views/parts/view-detail.ok.js +1 -0
- package/public/sections/views/parts/views-list.ok.js +1 -0
- package/public/sections/views/parts/views-overview.ok.js +1 -0
- package/public/setup-app.js +1 -0
- package/public/setup.html +1 -0
- package/public/site.webmanifest +1 -0
- package/public/stores/auth-store.js +1 -0
- package/public/stores/events-store.js +1 -0
- package/public/stores/functions-store.js +1 -0
- package/public/stores/okdb-store.js +1 -0
- package/public/stores/theme-store.js +1 -0
- package/public/styles.css +1 -0
- package/public/test-cron-input.html +10 -0
- package/public/test-json-input.html +101 -0
- package/public/util/permissions.js +1 -0
- package/public/util/sift-schema.js +1 -0
- package/public/vendor/okjs/ok.esm.min.js +2 -0
- package/public/vendor/okjs/toolkit/behavior/async.ok.js +1 -0
- package/public/vendor/okjs/toolkit/components/ok-chart.ok.js +1 -0
- package/public/vendor/okjs/toolkit/components/ok-doc-viewer.ok.js +1 -0
- package/public/vendor/okjs/toolkit/components/ok-marked.ok.js +1 -0
- package/public/vendor/okjs/toolkit/components/ok-monaco.ok.js +1 -0
- package/public/vendor/okjs/toolkit/core/ok-layer-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/core/ok-layer.ok.js +1 -0
- package/public/vendor/okjs/toolkit/core/ok-overlay.ok.js +1 -0
- package/public/vendor/okjs/toolkit/core/ok-sandbox.ok.js +1 -0
- package/public/vendor/okjs/toolkit/core/transition.ok.js +1 -0
- package/public/vendor/okjs/toolkit/core/virtualized.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-console-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-console.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-fps-monitor-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-fps-monitor.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-inspector-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-inspector.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-js-tree.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-timeline-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/devtools/ok-timeline.ok.js +1 -0
- package/public/vendor/okjs/toolkit/docs/doc-viewer.ok.js +1 -0
- package/public/vendor/okjs/toolkit/editor/ok-live-component.ok.js +1 -0
- package/public/vendor/okjs/toolkit/editor/ok-live-example.ok.js +1 -0
- package/public/vendor/okjs/toolkit/editor/ok-live-shell.ok.js +1 -0
- package/public/vendor/okjs/toolkit/elements/ok-dropdown.ok.js +1 -0
- package/public/vendor/okjs/toolkit/elements/ok-icon.ok.js +1 -0
- package/public/vendor/okjs/toolkit/elements/ok-select.ok.js +1 -0
- package/public/vendor/okjs/toolkit/elements/ok-table.ok.js +1 -0
- package/public/vendor/okjs/toolkit/errors/ok-crash-boundary.ok.js +1 -0
- package/public/vendor/okjs/toolkit/errors/ok-crash-info.ok.js +1 -0
- package/public/vendor/okjs/toolkit/i18n/i18n-editor-examples.ok.js +1 -0
- package/public/vendor/okjs/toolkit/i18n/i18n-editor.ok.js +1 -0
- package/public/vendor/okjs/toolkit/i18n/i18n-key-editor-tips.ok.js +1 -0
- package/public/vendor/okjs/toolkit/i18n/i18n-key-editor.ok.js +1 -0
- package/public/vendor/okjs/toolkit/i18n/i18n-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/i18n/ok-i18n.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-contextmenu.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-dismiss-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-draggable.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-flyover-panel.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-flyover.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-highlight-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-highlight.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-hotkeys-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-picker-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-popout-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-popout.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-portal-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/interaction/ok-submenu.ok.js +1 -0
- package/public/vendor/okjs/toolkit/layout/ok-resizer.ok.js +1 -0
- package/public/vendor/okjs/toolkit/manifest.js +1 -0
- package/public/vendor/okjs/toolkit/modals/ok-modal-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/modals/ok-modal.ok.js +1 -0
- package/public/vendor/okjs/toolkit/modals/ok-toast-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/modals/ok-window.ok.js +1 -0
- package/public/vendor/okjs/toolkit/navigation/hash-router.ok.js +1 -0
- package/public/vendor/okjs/toolkit/navigation/history-router.ok.js +1 -0
- package/public/vendor/okjs/toolkit/navigation/router.ok.js +1 -0
- package/public/vendor/okjs/toolkit/sync/reactive-sync-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/sync/reactive-sync.js +1 -0
- package/public/vendor/okjs/toolkit/theming/blocks/ok-design-button.css.js +1 -0
- package/public/vendor/okjs/toolkit/theming/blocks/ok-design-input.css.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-design-style.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-design-vars.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-design.ok.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-input.ok.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-service.ok.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-style.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-utils.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-variable.ok.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-vm.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor.ok.js +1 -0
- package/public/vendor/okjs/toolkit/theming/ok-theme.ok.js +1 -0
- package/public/view-models/type-query-vm.js +1 -0
- package/types/environment.d.ts +130 -0
- package/types/errors.d.ts +98 -0
- package/types/features/admin.d.ts +4 -0
- package/types/features/api.d.ts +18 -0
- package/types/features/auth.d.ts +31 -0
- package/types/features/embeddings.d.ts +39 -0
- package/types/features/engines.d.ts +23 -0
- package/types/features/files.d.ts +29 -0
- package/types/features/fts.d.ts +25 -0
- package/types/features/functions.d.ts +23 -0
- package/types/features/mcp.d.ts +17 -0
- package/types/features/pipelines.d.ts +19 -0
- package/types/features/queue.d.ts +189 -0
- package/types/features/sync.d.ts +34 -0
- package/types/features/time-machine.d.ts +32 -0
- package/types/features/views.d.ts +16 -0
- package/types/index.d.ts +153 -0
- package/types/options.d.ts +202 -0
package/docs/queue.md
ADDED
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
# Queue
|
|
2
|
+
|
|
3
|
+
OKDB has a built-in durable job queue.
|
|
4
|
+
|
|
5
|
+
Queue data lives in the **current environment**:
|
|
6
|
+
|
|
7
|
+
- `okdb.queue` uses the **default** environment
|
|
8
|
+
- `okdb.env('myenv').queue` uses that **custom** environment
|
|
9
|
+
|
|
10
|
+
Jobs survive restart, are stored as normal OKDB records, and can be listed, edited, retried, and processed by workers.
|
|
11
|
+
|
|
12
|
+
No Redis, no RabbitMQ. Just OKDB.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```javascript
|
|
19
|
+
const OKDB = require('./okdb');
|
|
20
|
+
|
|
21
|
+
async function main() {
|
|
22
|
+
const okdb = new OKDB('./db');
|
|
23
|
+
await okdb.open();
|
|
24
|
+
|
|
25
|
+
const worker = okdb.queue.worker(
|
|
26
|
+
'send-email',
|
|
27
|
+
async (payload, ctx) => {
|
|
28
|
+
await ctx.markProgress('sending email');
|
|
29
|
+
|
|
30
|
+
await sendEmail(payload.to, payload.subject, payload.orderId);
|
|
31
|
+
|
|
32
|
+
await ctx.okdb.put('email_log', payload.orderId, {
|
|
33
|
+
to: payload.to,
|
|
34
|
+
sentAt: Date.now(),
|
|
35
|
+
jobId: ctx.jobId,
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
concurrency: 4,
|
|
40
|
+
pollInterval: 100,
|
|
41
|
+
ttl: 30_000,
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const jobId = await okdb.queue.enqueue(
|
|
46
|
+
'send-email',
|
|
47
|
+
{
|
|
48
|
+
to: 'alice@example.com',
|
|
49
|
+
subject: 'Your order shipped',
|
|
50
|
+
orderId: 'o42',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
max_tries: 3,
|
|
54
|
+
retry_delay: 1000,
|
|
55
|
+
backoff_multiplier: 2,
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
console.log('enqueued', jobId);
|
|
60
|
+
|
|
61
|
+
// later
|
|
62
|
+
await worker.stop();
|
|
63
|
+
await okdb.close();
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Environments
|
|
70
|
+
|
|
71
|
+
Queue data is **not** stored in a special dedicated `queue/` environment.
|
|
72
|
+
|
|
73
|
+
Instead:
|
|
74
|
+
|
|
75
|
+
- `okdb.queue.enqueue(...)` stores queue records in `default`
|
|
76
|
+
- `customEnv.queue.enqueue(...)` stores queue records in `customEnv`
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
const okdb = new OKDB('./db');
|
|
82
|
+
await okdb.open();
|
|
83
|
+
|
|
84
|
+
const jobsEnv = await okdb.createEnvironment('jobs');
|
|
85
|
+
|
|
86
|
+
await okdb.queue.enqueue('default-task', { a: 1 });
|
|
87
|
+
await jobsEnv.queue.enqueue('custom-task', { b: 2 });
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This is useful when you want separate queues per environment.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Enqueuing jobs
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
const id = await okdb.queue.enqueue('process-image', {
|
|
98
|
+
fileId: 'f1',
|
|
99
|
+
userId: 'u1',
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
console.log(id); // UUID string
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Signature
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
await okdb.queue.enqueue(type, payload, options);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- `type` — non-empty job type string
|
|
112
|
+
- `payload` — any serialisable value; stored separately from job metadata
|
|
113
|
+
- `options` — scheduling / retry / routing metadata
|
|
114
|
+
|
|
115
|
+
### Enqueue options
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
await okdb.queue.enqueue(
|
|
119
|
+
'process-image',
|
|
120
|
+
{ fileId: 'f1' },
|
|
121
|
+
{
|
|
122
|
+
when: Date.now() + 5000, // schedule in the future
|
|
123
|
+
priority: 10,
|
|
124
|
+
tags: ['images', 'urgent'],
|
|
125
|
+
bucket: 'gpu-workers',
|
|
126
|
+
bucket_tokens: 1,
|
|
127
|
+
max_tries: 3, // null = unlimited
|
|
128
|
+
retry_delay: 2000,
|
|
129
|
+
backoff_multiplier: 2.0,
|
|
130
|
+
cron: '0 * * * *',
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Notes:
|
|
136
|
+
|
|
137
|
+
- `priority` is an integer
|
|
138
|
+
- `tags` can be a string or array of strings
|
|
139
|
+
- `bucket` and `bucket_tokens` integrate with token buckets
|
|
140
|
+
- `max_tries: 1` means “try once, then fail permanently”
|
|
141
|
+
- `max_tries: null` means unlimited retries
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Processing jobs with `worker(...)`
|
|
146
|
+
|
|
147
|
+
Use a normal in-process worker like this:
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
const worker = okdb.queue.worker(
|
|
151
|
+
'send-email',
|
|
152
|
+
async (payload, ctx) => {
|
|
153
|
+
await ctx.markProgress('validating');
|
|
154
|
+
|
|
155
|
+
if (!payload.to) throw new Error('missing recipient');
|
|
156
|
+
|
|
157
|
+
await ctx.markProgress('sending');
|
|
158
|
+
await sendEmail(payload.to, payload.subject);
|
|
159
|
+
|
|
160
|
+
await ctx.okdb.put('email_log', payload.orderId, {
|
|
161
|
+
to: payload.to,
|
|
162
|
+
sentAt: Date.now(),
|
|
163
|
+
jobId: ctx.jobId,
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
concurrency: 2,
|
|
168
|
+
pollInterval: 250,
|
|
169
|
+
ttl: 30_000,
|
|
170
|
+
onPermanentFail: async (job, err) => {
|
|
171
|
+
console.error('permanently failed', job.id, err.message);
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Handler signature
|
|
178
|
+
|
|
179
|
+
The handler receives:
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
async (payload, ctx) => { ... }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Where `ctx` contains:
|
|
186
|
+
|
|
187
|
+
- `ctx.okdb` — the root `OKDB` instance
|
|
188
|
+
- `ctx.jobId` — queue job id
|
|
189
|
+
- `ctx.heartbeat()` — extend the claim TTL for long-running jobs
|
|
190
|
+
- `ctx.markProgress(message)` — update the job's `progress` field
|
|
191
|
+
|
|
192
|
+
These local worker helpers now map to the same public queue API that remote workers can use:
|
|
193
|
+
|
|
194
|
+
- `okdb.queue.claim(type, options)`
|
|
195
|
+
- `okdb.queue.markJobHeartbeat(jobId, claimId, ttl?)`
|
|
196
|
+
- `okdb.queue.markJobProgress(jobId, claimId, message)`
|
|
197
|
+
- `okdb.queue.markJobComplete(jobId, claimId, result?)`
|
|
198
|
+
- `okdb.queue.markJobFail(jobId, claimId, error, code?)`
|
|
199
|
+
|
|
200
|
+
### Important note
|
|
201
|
+
|
|
202
|
+
`worker(...)` runs in the **same Node process** unless you explicitly use `spawn(...)` or a separate worker process yourself.
|
|
203
|
+
|
|
204
|
+
That means:
|
|
205
|
+
|
|
206
|
+
- great for I/O-heavy jobs
|
|
207
|
+
- not isolation from CPU-heavy work
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Worker options
|
|
212
|
+
|
|
213
|
+
### `pollInterval`
|
|
214
|
+
|
|
215
|
+
How long to sleep when the queue is empty.
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
{
|
|
219
|
+
pollInterval: 100;
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### `concurrency`
|
|
224
|
+
|
|
225
|
+
How many jobs to process in parallel **inside the same process**.
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
{
|
|
229
|
+
concurrency: 4;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
This is implemented as multiple independent claim/handle lanes.
|
|
234
|
+
|
|
235
|
+
### `ttl`
|
|
236
|
+
|
|
237
|
+
Claim timeout in ms.
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
{
|
|
241
|
+
ttl: 30_000;
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
If your worker dies or stops heartbeating, expired running jobs are re-queued by reconciliation.
|
|
246
|
+
|
|
247
|
+
### `onPermanentFail`
|
|
248
|
+
|
|
249
|
+
Called after a job permanently fails.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Remote / external workers
|
|
254
|
+
|
|
255
|
+
If your workers run outside the embedded Node.js process, use the public queue lifecycle methods directly or call the equivalent HTTP endpoints.
|
|
256
|
+
|
|
257
|
+
### Public queue methods
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
260
|
+
const claimed = await okdb.queue.claim('send-email', { ttl: 30_000 });
|
|
261
|
+
if (!claimed) return;
|
|
262
|
+
|
|
263
|
+
await okdb.queue.markJobProgress(claimed.id, claimed.claim_id, 'sending');
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
await sendEmail(claimed.payload.to, claimed.payload.subject);
|
|
267
|
+
await okdb.queue.markJobComplete(claimed.id, claimed.claim_id, { delivered: true });
|
|
268
|
+
} catch (err) {
|
|
269
|
+
await okdb.queue.markJobFail(claimed.id, claimed.claim_id, err, 'send_failed');
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Claim ownership contract
|
|
274
|
+
|
|
275
|
+
Remote lifecycle operations require the active `claim_id` returned by `claim(...)`.
|
|
276
|
+
|
|
277
|
+
- only the current claim holder may heartbeat, write progress, complete, or fail the job
|
|
278
|
+
- stale workers are rejected once the claim changes or expires
|
|
279
|
+
- this prevents duplicate workers from mutating the same running job
|
|
280
|
+
|
|
281
|
+
### HTTP endpoints for remote workers
|
|
282
|
+
|
|
283
|
+
The queue HTTP API now exposes the full remote-worker lifecycle:
|
|
284
|
+
|
|
285
|
+
- `POST /api/queue/claim/:type`
|
|
286
|
+
- `POST /api/queue/job/:id/heartbeat`
|
|
287
|
+
- `POST /api/queue/job/:id/progress`
|
|
288
|
+
- `POST /api/queue/job/:id/complete`
|
|
289
|
+
- `POST /api/queue/job/:id/fail`
|
|
290
|
+
|
|
291
|
+
Example:
|
|
292
|
+
|
|
293
|
+
```text
|
|
294
|
+
// claim
|
|
295
|
+
POST /api/queue/claim/send-email
|
|
296
|
+
{ "options": { "ttl": 30000 } }
|
|
297
|
+
|
|
298
|
+
// progress
|
|
299
|
+
POST /api/queue/job/<id>/progress
|
|
300
|
+
{ "claim_id": "<claim>", "progress": "sending" }
|
|
301
|
+
|
|
302
|
+
// complete
|
|
303
|
+
POST /api/queue/job/<id>/complete
|
|
304
|
+
{ "claim_id": "<claim>", "result": { "delivered": true } }
|
|
305
|
+
|
|
306
|
+
// fail
|
|
307
|
+
POST /api/queue/job/<id>/fail
|
|
308
|
+
{ "claim_id": "<claim>", "code": "send_failed", "message": "smtp timeout" }
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Spawned workers
|
|
314
|
+
|
|
315
|
+
If you want queue handling in a **separate Node process**, use `spawn(...)`:
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
const spawned = await okdb.queue.spawn('send-email', './workers/email.js', {
|
|
319
|
+
concurrency: 4,
|
|
320
|
+
pollInterval: 100,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// later
|
|
324
|
+
await spawned.stop();
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
The module must export a function:
|
|
328
|
+
|
|
329
|
+
```javascript
|
|
330
|
+
module.exports = async function (payload, ctx) {
|
|
331
|
+
await ctx.okdb.put('email_log', payload.orderId, {
|
|
332
|
+
sentAt: Date.now(),
|
|
333
|
+
jobId: ctx.jobId,
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
The child process opens the same OKDB path and receives the same `ctx.okdb` semantics as a normal worker.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Job lifecycle
|
|
343
|
+
|
|
344
|
+
```text
|
|
345
|
+
pending → running → done
|
|
346
|
+
└→ pending (retry)
|
|
347
|
+
└→ failed
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
In more detail:
|
|
351
|
+
|
|
352
|
+
- `pending` — ready to be claimed
|
|
353
|
+
- `running` — claimed by a worker and currently in-flight
|
|
354
|
+
- `done` — completed successfully
|
|
355
|
+
- `failed` — permanently failed after all tries are exhausted
|
|
356
|
+
|
|
357
|
+
When a running job's claim expires, reconciliation moves it back to `pending`.
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Heartbeats and reconciliation
|
|
362
|
+
|
|
363
|
+
For long-running jobs, call `ctx.heartbeat()` periodically:
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
okdb.queue.worker(
|
|
367
|
+
'import',
|
|
368
|
+
async (payload, ctx) => {
|
|
369
|
+
for (let i = 0; i < 10; i++) {
|
|
370
|
+
await processChunk(i);
|
|
371
|
+
await ctx.heartbeat();
|
|
372
|
+
await ctx.markProgress(`chunk ${i + 1}/10`);
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{ ttl: 5000 },
|
|
376
|
+
);
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
You can also manually trigger reconciliation:
|
|
380
|
+
|
|
381
|
+
```javascript
|
|
382
|
+
await okdb.queue._reconcile();
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
The admin UI also exposes reconcile actions.
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Listing jobs
|
|
390
|
+
|
|
391
|
+
```javascript
|
|
392
|
+
const { items, cursor } = await okdb.queue.list({
|
|
393
|
+
type: 'send-email',
|
|
394
|
+
status: 'pending',
|
|
395
|
+
sort: 'when', // 'when' | 'priority'
|
|
396
|
+
direction: 'asc',
|
|
397
|
+
limit: 50,
|
|
398
|
+
cursor: null,
|
|
399
|
+
});
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Supported filters/options:
|
|
403
|
+
|
|
404
|
+
- `type`
|
|
405
|
+
- `status`
|
|
406
|
+
- `bucket`
|
|
407
|
+
- `tag`
|
|
408
|
+
- `sort`
|
|
409
|
+
- `direction`
|
|
410
|
+
- `limit`
|
|
411
|
+
- `cursor`
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Getting and updating one job
|
|
416
|
+
|
|
417
|
+
### Get a job
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
const job = await okdb.queue.getJob(jobId);
|
|
421
|
+
|
|
422
|
+
console.log(job.status);
|
|
423
|
+
console.log(job.payload);
|
|
424
|
+
console.log(job.progress);
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
`getJob()` returns job metadata **plus payload**.
|
|
428
|
+
|
|
429
|
+
### Update a job
|
|
430
|
+
|
|
431
|
+
```javascript
|
|
432
|
+
await okdb.queue.updateJob(jobId, {
|
|
433
|
+
payload: { fileId: 'f1', force: true },
|
|
434
|
+
priority: 9,
|
|
435
|
+
tags: ['edited', 'manual'],
|
|
436
|
+
progress: 'manually adjusted',
|
|
437
|
+
status_message: 'edited from admin ui',
|
|
438
|
+
retry_delay: 500,
|
|
439
|
+
});
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Editable fields currently include:
|
|
443
|
+
|
|
444
|
+
- `type`
|
|
445
|
+
- `payload`
|
|
446
|
+
- `when`
|
|
447
|
+
- `priority`
|
|
448
|
+
- `tags`
|
|
449
|
+
- `bucket`
|
|
450
|
+
- `bucket_tokens`
|
|
451
|
+
- `cron`
|
|
452
|
+
- `max_tries`
|
|
453
|
+
- `retry_delay`
|
|
454
|
+
- `backoff_multiplier`
|
|
455
|
+
- `progress`
|
|
456
|
+
- `status_message`
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## Retrying, removing, and clearing jobs
|
|
461
|
+
|
|
462
|
+
### Retry one job
|
|
463
|
+
|
|
464
|
+
```javascript
|
|
465
|
+
await okdb.queue.retryJob(jobId);
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
This resets the job back to `pending` and resets `tries` to `0`.
|
|
469
|
+
|
|
470
|
+
### Remove one job
|
|
471
|
+
|
|
472
|
+
```javascript
|
|
473
|
+
await okdb.queue.removeJob(jobId);
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
This deletes both the job metadata and its payload.
|
|
477
|
+
|
|
478
|
+
### Bulk cleanup helpers
|
|
479
|
+
|
|
480
|
+
```javascript
|
|
481
|
+
await okdb.queue.clearDone();
|
|
482
|
+
await okdb.queue.clearFailed();
|
|
483
|
+
await okdb.queue.clearStuck();
|
|
484
|
+
await okdb.queue.retryFailed();
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Each method also accepts optional `type` and `limit` parameters.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## Buckets (token-bucket rate limiting)
|
|
492
|
+
|
|
493
|
+
Create a bucket:
|
|
494
|
+
|
|
495
|
+
```javascript
|
|
496
|
+
await okdb.queue.addBucket('gpu-workers', {
|
|
497
|
+
capacity: 100,
|
|
498
|
+
tokens: 100,
|
|
499
|
+
refill_amount: 10,
|
|
500
|
+
refill_every: 1000,
|
|
501
|
+
});
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Update a bucket:
|
|
505
|
+
|
|
506
|
+
```javascript
|
|
507
|
+
await okdb.queue.updateBucket('gpu-workers', {
|
|
508
|
+
tokens: 50,
|
|
509
|
+
refill_amount: 20,
|
|
510
|
+
});
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Remove a bucket:
|
|
514
|
+
|
|
515
|
+
```javascript
|
|
516
|
+
await okdb.queue.removeBucket('gpu-workers');
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Manually claim tokens:
|
|
520
|
+
|
|
521
|
+
```javascript
|
|
522
|
+
const ok = await okdb.queue.tryClaimTokens('gpu-workers', 2);
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Jobs can reference a bucket via `enqueue(..., { bucket, bucket_tokens })`.
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## Cron support
|
|
530
|
+
|
|
531
|
+
If you use `cron`, you must configure `queue.cron_next`:
|
|
532
|
+
|
|
533
|
+
```javascript
|
|
534
|
+
const Croner = require('croner');
|
|
535
|
+
|
|
536
|
+
const okdb = new OKDB('./db', {
|
|
537
|
+
queue: {
|
|
538
|
+
cron_next: (expr, fromMs) => {
|
|
539
|
+
return new Croner(expr, { currentDate: new Date(fromMs) }).nextRun().getTime();
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Then enqueue recurring work:
|
|
546
|
+
|
|
547
|
+
```javascript
|
|
548
|
+
await okdb.queue.enqueue(
|
|
549
|
+
'daily-report',
|
|
550
|
+
{ reportType: 'summary' },
|
|
551
|
+
{
|
|
552
|
+
cron: '0 8 * * *',
|
|
553
|
+
},
|
|
554
|
+
);
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Events
|
|
560
|
+
|
|
561
|
+
Queue lifecycle events are emitted on **`okdb.events`**, not on `okdb.queue.events`.
|
|
562
|
+
|
|
563
|
+
Current low-frequency emitted events include:
|
|
564
|
+
|
|
565
|
+
- `queue:enqueued`
|
|
566
|
+
- `queue:done`
|
|
567
|
+
- `queue:failed`
|
|
568
|
+
- `queue:retry`
|
|
569
|
+
- `queue:removed`
|
|
570
|
+
- `queue:reconciled`
|
|
571
|
+
|
|
572
|
+
Example:
|
|
573
|
+
|
|
574
|
+
```javascript
|
|
575
|
+
okdb.events.on('queue:done', ({ id, type }) => {
|
|
576
|
+
console.log('done', id, type);
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
okdb.events.on('queue:failed', ({ id, type, status_code }) => {
|
|
580
|
+
console.log('failed', id, type, status_code);
|
|
581
|
+
});
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### About filtering by type or key
|
|
585
|
+
|
|
586
|
+
Today, filtering by job type or job id is best done in your handler:
|
|
587
|
+
|
|
588
|
+
```javascript
|
|
589
|
+
okdb.events.on('queue:done', (ev) => {
|
|
590
|
+
if (ev.type !== 'send-email') return;
|
|
591
|
+
console.log('email job done', ev.id);
|
|
592
|
+
});
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
If a richer queue-specific event subscription API is added later, it will likely build on top of these base events.
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## Sync behaviour
|
|
600
|
+
|
|
601
|
+
Queue data lives in the current environment, so queue sync follows that environment's sync settings.
|
|
602
|
+
|
|
603
|
+
That means:
|
|
604
|
+
|
|
605
|
+
- a job enqueued in a synced env can replicate to peers
|
|
606
|
+
- a worker on another node/process can consume from the same synced data
|
|
607
|
+
- retry/failure state also follows the same environment data
|
|
608
|
+
|
|
609
|
+
If you want queue isolation, use a separate environment with the sync behavior you want.
|
|
610
|
+
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
## Queue-worker engine
|
|
614
|
+
|
|
615
|
+
For persistent, self-managing workers that use stored functions, see **queue-worker engines** in [Pipelines](./pipelines.md).
|
|
616
|
+
|
|
617
|
+
The queue-worker engine is a pipeline-compatible engine type that:
|
|
618
|
+
|
|
619
|
+
- claims jobs from the queue automatically
|
|
620
|
+
- invokes a stored function for each claimed payload
|
|
621
|
+
- handles completion/failure using normal queue semantics
|
|
622
|
+
|
|
623
|
+
Worker `concurrency` controls job throughput. The function runner pool scales automatically to support it — no manual pool sizing is needed.
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
## Admin UI
|
|
628
|
+
|
|
629
|
+
The admin queue UI supports:
|
|
630
|
+
|
|
631
|
+
- filtering by status and type
|
|
632
|
+
- retry / cancel / delete
|
|
633
|
+
- bulk clear / bulk retry actions
|
|
634
|
+
- viewing progress
|
|
635
|
+
- editing payload and queue settings for a job
|
|
636
|
+
|
|
637
|
+
Expanded rows show key metadata, and the edit dialog allows modifying payload and most queue settings without editing raw `~queue_jobs` records directly.
|