@kubun/plugin-workflow 0.14.0 → 0.15.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/lib/engine.js +16 -22
- package/lib/schema.js +26 -4
- package/package.json +11 -11
package/lib/engine.js
CHANGED
|
@@ -398,6 +398,9 @@ export function createWorkflowEngine(deps) {
|
|
|
398
398
|
}
|
|
399
399
|
registry.set(def.name, erased);
|
|
400
400
|
},
|
|
401
|
+
isManagedWorkflow (name) {
|
|
402
|
+
return registry.get(name)?.managed === true;
|
|
403
|
+
},
|
|
401
404
|
defineQueue,
|
|
402
405
|
async schedule (name, params, when) {
|
|
403
406
|
const s = await store();
|
|
@@ -441,28 +444,19 @@ export function createWorkflowEngine(deps) {
|
|
|
441
444
|
// Deterministic id so a re-arm across restarts targets the same row.
|
|
442
445
|
const id = `${name}:${opts.subjectKey}`;
|
|
443
446
|
const at = now();
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
} else {
|
|
458
|
-
// Reactivation: re-arm eagerly, preserving the stored streak.
|
|
459
|
-
await s.advanceScheduleAdaptive(id, {
|
|
460
|
-
nextRun: at + opts.policy.changed,
|
|
461
|
-
lastOutcome: existing.last_outcome,
|
|
462
|
-
consecutiveCount: existing.consecutive_count
|
|
463
|
-
}, at);
|
|
464
|
-
await s.setScheduleEnabled(id, true, at);
|
|
465
|
-
}
|
|
447
|
+
// Insert-or-arm in one atomic write: a fresh subject is created armed, an
|
|
448
|
+
// existing one is re-armed eagerly with its outcome streak preserved.
|
|
449
|
+
// Concurrent enables of the same subject converge instead of racing to a
|
|
450
|
+
// PK conflict.
|
|
451
|
+
await s.upsertAdaptiveSchedule({
|
|
452
|
+
id,
|
|
453
|
+
workflowName: name,
|
|
454
|
+
params,
|
|
455
|
+
policy: opts.policy,
|
|
456
|
+
nextRun: at + opts.policy.changed,
|
|
457
|
+
enabled: true,
|
|
458
|
+
reactivate: opts.reactivate
|
|
459
|
+
}, at);
|
|
466
460
|
const handle = {
|
|
467
461
|
id,
|
|
468
462
|
async disable () {
|
package/lib/schema.js
CHANGED
|
@@ -105,15 +105,37 @@ function requireWorkflow(ctx) {
|
|
|
105
105
|
function decodeScheduleID(id) {
|
|
106
106
|
return PluginNodeID.fromString(id).localID;
|
|
107
107
|
}
|
|
108
|
+
// Refusal for a managed schedule reached through the generic control surface.
|
|
109
|
+
// A managed schedule is owned by its workflow's plugin and controlled only
|
|
110
|
+
// through that plugin's own owner-scoped path.
|
|
111
|
+
const MANAGED_SCHEDULE_ERROR = 'schedule is managed by its owning plugin';
|
|
108
112
|
export function createWorkflowContextFactory(api) {
|
|
113
|
+
// A managed schedule is excluded from the generic controls: queries omit it and
|
|
114
|
+
// mutations refuse it. The connector reaches its own schedules through the
|
|
115
|
+
// engine WorkflowAPI directly (not this context), so its owner-scoped path is
|
|
116
|
+
// untouched.
|
|
117
|
+
const isManaged = (sync)=>sync != null && api.isManagedWorkflow(sync.workflowName);
|
|
109
118
|
return ()=>({
|
|
110
119
|
get: (instanceID)=>api.get(instanceID),
|
|
111
120
|
list: (filter)=>api.list(filter),
|
|
112
121
|
subscribeToWorkflowEvents: (instanceID)=>subscribeToWorkflowEvents(api.events, instanceID),
|
|
113
|
-
getPeriodicSync: (scheduleID)=>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
122
|
+
getPeriodicSync: async (scheduleID)=>{
|
|
123
|
+
const sync = await api.getPeriodicSync(scheduleID);
|
|
124
|
+
return isManaged(sync) ? null : sync;
|
|
125
|
+
},
|
|
126
|
+
listPeriodicSyncs: async (workflowName)=>(await api.listPeriodicSyncs(workflowName)).filter((sync)=>!api.isManagedWorkflow(sync.workflowName)),
|
|
127
|
+
setPeriodicSyncEnabled: async (scheduleID, enabled)=>{
|
|
128
|
+
if (isManaged(await api.getPeriodicSync(scheduleID))) {
|
|
129
|
+
throw new Error(MANAGED_SCHEDULE_ERROR);
|
|
130
|
+
}
|
|
131
|
+
return api.setPeriodicSyncEnabled(scheduleID, enabled);
|
|
132
|
+
},
|
|
133
|
+
setPeriodicSyncPolicy: async (scheduleID, policy)=>{
|
|
134
|
+
if (isManaged(await api.getPeriodicSync(scheduleID))) {
|
|
135
|
+
throw new Error(MANAGED_SCHEDULE_ERROR);
|
|
136
|
+
}
|
|
137
|
+
return api.setPeriodicSyncPolicy(scheduleID, policy);
|
|
138
|
+
}
|
|
117
139
|
});
|
|
118
140
|
}
|
|
119
141
|
// ms-epoch timestamps are exposed as `Float` (JS number), matching how the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/plugin-workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"keywords": [],
|
|
5
5
|
"license": "see LICENSE.md",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -15,21 +15,21 @@
|
|
|
15
15
|
"LICENSE.md"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@kubun/db": "^0.
|
|
19
|
-
"@kubun/engine": "^0.
|
|
20
|
-
"@kubun/graphql": "^0.
|
|
21
|
-
"@kubun/id": "^0.
|
|
22
|
-
"@kubun/logger": "^0.
|
|
23
|
-
"@kubun/plugin-workflow-api": "^0.
|
|
24
|
-
"@kubun/store-workflow": "^0.
|
|
18
|
+
"@kubun/db": "^0.15.0",
|
|
19
|
+
"@kubun/engine": "^0.15.0",
|
|
20
|
+
"@kubun/graphql": "^0.15.0",
|
|
21
|
+
"@kubun/id": "^0.15.0",
|
|
22
|
+
"@kubun/logger": "^0.15.0",
|
|
23
|
+
"@kubun/plugin-workflow-api": "^0.15.0",
|
|
24
|
+
"@kubun/store-workflow": "^0.15.0",
|
|
25
25
|
"@sozai/event": "^0.1.3",
|
|
26
26
|
"@sozai/flow": "^0.3.1",
|
|
27
27
|
"@sozai/runtime": "^0.1.0",
|
|
28
|
-
"@sozai/schema": "^0.1.
|
|
28
|
+
"@sozai/schema": "^0.1.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@kubun/db-better-sqlite": "^0.
|
|
32
|
-
"@kubun/db-postgres": "^0.
|
|
31
|
+
"@kubun/db-better-sqlite": "^0.15.0",
|
|
32
|
+
"@kubun/db-postgres": "^0.15.0",
|
|
33
33
|
"@testcontainers/postgresql": "^12.1.0"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|