@reventlessdev/reventless-core 3.0.0-alpha.294 → 3.0.0-alpha.296
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/CHANGELOG.md +39 -0
- package/package.json +8 -8
- package/src/admin/Platform_ComponentDefinitionsApi.res +3 -1
- package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +5 -1
- package/src/components/AutomationSlice/AutomationSlice.res +2 -0
- package/src/components/AutomationSlice/AutomationSlice_Builder.res +133 -8
- package/src/components/AutomationSlice/AutomationSlice_Builder.res.mjs +89 -7
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +136 -3
- package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +122 -4
- package/src/components/AutomationSlice/AutomationSlice_Route.res +3 -1
- package/src/components/AutomationSlice/AutomationSlice_Route.res.mjs +2 -1
- package/src/components/AutomationSlice/AutomationSlice_Schedules.res +149 -0
- package/src/components/AutomationSlice/AutomationSlice_Schedules.res.mjs +193 -0
- package/src/components/Dcb/Dcb_Builder.res +28 -4
- package/src/components/Dcb/Dcb_Builder.res.mjs +27 -5
- package/src/plugin/component/Plugin_Builder.res +10 -3
- package/src/plugin/component/Plugin_Builder.res.mjs +8 -2
- package/src/plugin/component/Plugin_Structure.res +7 -0
- package/src/plugin/component/Plugin_Structure.res.mjs +5 -2
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res +1 -1
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +1 -1
- package/src/util/ScheduleOps.res +1 -55
- package/src/util/ScheduleOps.res.mjs +10 -57
- package/src/util/ScheduleTime.res +266 -0
- package/src/util/ScheduleTime.res.mjs +451 -0
- package/tests/admin/AdminApiSchemaDriftTest.res +1 -0
- package/tests/admin/AdminApiSchemaDriftTest.res.mjs +4 -1
- package/tests/automationslice/AutomationSliceSchedulesTest.res +143 -0
- package/tests/automationslice/AutomationSliceSchedulesTest.res.mjs +247 -0
- package/tests/util/ScheduleTimeTest.res +256 -0
- package/tests/util/ScheduleTimeTest.res.mjs +532 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Sury from "sury";
|
|
4
|
+
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
5
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
6
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
|
+
import * as Clock$Reventless from "@reventlessdev/reventless-spec/src/components/Clock.res.mjs";
|
|
8
|
+
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
9
|
+
import * as Schedule$Reventless from "@reventlessdev/reventless-spec/src/types/Schedule.res.mjs";
|
|
10
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
11
|
+
import * as ScheduleTime$ReventlessCore from "../../util/ScheduleTime.res.mjs";
|
|
12
|
+
|
|
13
|
+
let declared = "declared";
|
|
14
|
+
|
|
15
|
+
let rowSchema = Sury.$schema(s => ({
|
|
16
|
+
key: s.m(Sury.string),
|
|
17
|
+
time: s.m(Sury.$option(Sury.string)),
|
|
18
|
+
setBy: s.m(Sury.string),
|
|
19
|
+
setAt: s.m(Sury.string)
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
function encodeTime(time) {
|
|
23
|
+
return JSON.stringify(Util_Sury$Reventless.toJson(time, Schedule$Reventless.timeSchema));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function decodeTime(text) {
|
|
27
|
+
return Util_Sury$Reventless.fromJson(JSON.parse(text), Schedule$Reventless.timeSchema);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function timeOf(row) {
|
|
31
|
+
return Stdlib_Option.map(row.time, decodeTime);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function iso(millis) {
|
|
35
|
+
return new Date(millis).toISOString();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function clearRow(rows, key, setBy, setAt) {
|
|
39
|
+
if (key === Clock$Reventless.defaultKey) {
|
|
40
|
+
rows[key] = {
|
|
41
|
+
key: key,
|
|
42
|
+
setBy: setBy,
|
|
43
|
+
setAt: setAt
|
|
44
|
+
};
|
|
45
|
+
return;
|
|
46
|
+
} else {
|
|
47
|
+
return Stdlib_Dict.$$delete(rows, key);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function apply(rows, change, setBy, recordedAt) {
|
|
52
|
+
if (change.TAG === "Set") {
|
|
53
|
+
let wanted = change.time;
|
|
54
|
+
let key = change.key;
|
|
55
|
+
let errs = ScheduleTime$ReventlessCore.errors(wanted);
|
|
56
|
+
if (errs.length !== 0) {
|
|
57
|
+
return {
|
|
58
|
+
TAG: "Error",
|
|
59
|
+
_0: `schedule ` + key + `: ` + errs.join("; ")
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
let resolved = ScheduleTime$ReventlessCore.resolveOnce(wanted, recordedAt);
|
|
63
|
+
rows[key] = {
|
|
64
|
+
key: key,
|
|
65
|
+
time: encodeTime(resolved),
|
|
66
|
+
setBy: setBy,
|
|
67
|
+
setAt: new Date(recordedAt).toISOString()
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
TAG: "Ok",
|
|
71
|
+
_0: {
|
|
72
|
+
TAG: "Put",
|
|
73
|
+
key: key,
|
|
74
|
+
time: resolved
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
let cleared = change.key;
|
|
79
|
+
clearRow(rows, cleared, setBy, new Date(recordedAt).toISOString());
|
|
80
|
+
return {
|
|
81
|
+
TAG: "Ok",
|
|
82
|
+
_0: {
|
|
83
|
+
TAG: "Remove",
|
|
84
|
+
key: cleared
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function fired(rows, key) {
|
|
90
|
+
Stdlib_Option.forEach(rows[key], row => {
|
|
91
|
+
let match = Stdlib_Option.map(row.time, decodeTime);
|
|
92
|
+
if (match === undefined) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
switch (match.TAG) {
|
|
96
|
+
case "Every" :
|
|
97
|
+
case "Calendar" :
|
|
98
|
+
return;
|
|
99
|
+
case "Once" :
|
|
100
|
+
return clearRow(rows, key, row.setBy, row.setAt);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function declare(rows, declaredTime, now) {
|
|
106
|
+
let match = rows[Clock$Reventless.defaultKey];
|
|
107
|
+
if (declaredTime !== undefined) {
|
|
108
|
+
if (match !== undefined && !(match.setBy === declared && Primitive_object.notequal(match.time, encodeTime(declaredTime)))) {
|
|
109
|
+
return;
|
|
110
|
+
} else {
|
|
111
|
+
rows[Clock$Reventless.defaultKey] = {
|
|
112
|
+
key: Clock$Reventless.defaultKey,
|
|
113
|
+
time: encodeTime(declaredTime),
|
|
114
|
+
setBy: declared,
|
|
115
|
+
setAt: new Date(now).toISOString()
|
|
116
|
+
};
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
} else if (match !== undefined && match.setBy === declared) {
|
|
120
|
+
return Stdlib_Dict.$$delete(rows, Clock$Reventless.defaultKey);
|
|
121
|
+
} else {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function isPast(time, now) {
|
|
127
|
+
switch (time.TAG) {
|
|
128
|
+
case "Every" :
|
|
129
|
+
case "Calendar" :
|
|
130
|
+
return false;
|
|
131
|
+
case "Once" :
|
|
132
|
+
return Stdlib_Option.isNone(ScheduleTime$ReventlessCore.nextFiring(time, now));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function reconcile(rows, platform, declaredTime, now) {
|
|
137
|
+
declare(rows, declaredTime, now);
|
|
138
|
+
let live = Stdlib_Array.filterMap(Object.values(rows), row => {
|
|
139
|
+
let time = Stdlib_Option.map(row.time, decodeTime);
|
|
140
|
+
if (time !== undefined) {
|
|
141
|
+
if (isPast(time, now)) {
|
|
142
|
+
clearRow(rows, row.key, row.setBy, row.setAt);
|
|
143
|
+
return;
|
|
144
|
+
} else {
|
|
145
|
+
return [
|
|
146
|
+
row,
|
|
147
|
+
time
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
let held = await platform.names();
|
|
153
|
+
for (let i = 0, i_finish = live.length; i < i_finish; ++i) {
|
|
154
|
+
let match = live[i];
|
|
155
|
+
let row = match[0];
|
|
156
|
+
if (row.setBy === declared || !held.includes(platform.nameOf(row.key))) {
|
|
157
|
+
await platform.put(row.key, match[1]);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
let wanted = live.map(param => platform.nameOf(param[0].key));
|
|
161
|
+
let extra = held.filter(name => !wanted.includes(name));
|
|
162
|
+
for (let i$1 = 0, i_finish$1 = extra.length; i$1 < i_finish$1; ++i$1) {
|
|
163
|
+
await platform.removeName(extra[i$1]);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function tell(platform, changes) {
|
|
168
|
+
for (let i = 0, i_finish = changes.length; i < i_finish; ++i) {
|
|
169
|
+
let match = changes[i];
|
|
170
|
+
if (match.TAG === "Put") {
|
|
171
|
+
await platform.put(match.key, match.time);
|
|
172
|
+
} else {
|
|
173
|
+
await platform.removeName(platform.nameOf(match.key));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export {
|
|
179
|
+
declared,
|
|
180
|
+
rowSchema,
|
|
181
|
+
encodeTime,
|
|
182
|
+
decodeTime,
|
|
183
|
+
timeOf,
|
|
184
|
+
iso,
|
|
185
|
+
clearRow,
|
|
186
|
+
apply,
|
|
187
|
+
fired,
|
|
188
|
+
declare,
|
|
189
|
+
isPast,
|
|
190
|
+
reconcile,
|
|
191
|
+
tell,
|
|
192
|
+
}
|
|
193
|
+
/* rowSchema Not a pure module */
|
|
@@ -188,11 +188,13 @@ module Make = (
|
|
|
188
188
|
// its own `sourceEventSchema`. Validation contributes one entry per
|
|
189
189
|
// (slice, source) pair so unknown variants surface against the right
|
|
190
190
|
// mapping context.
|
|
191
|
+
// The Clock's ticks come from the slice's schedules, not from a slice.
|
|
191
192
|
automationSlices->Array.flatMap((module(A: AutomationSlice.T)) =>
|
|
192
|
-
A.Automation.mappings->Array.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
A.Automation.mappings->Array.filterMap((module(M: A.Automation.Mapping)) =>
|
|
194
|
+
M.sourceName == Reventless.Clock.name
|
|
195
|
+
? None
|
|
196
|
+
: Some((A.Spec.name, M.sourceEventSchema->S.castToUnknown))
|
|
197
|
+
)
|
|
196
198
|
),
|
|
197
199
|
)
|
|
198
200
|
->Array.concat(
|
|
@@ -664,6 +666,12 @@ module Make = (
|
|
|
664
666
|
automationSlices->Array.forEach((module(A: AutomationSlice.T)) => {
|
|
665
667
|
let qn = Api_Naming.queryFieldNamesForSliceQueryDb(~plugin=name, ~queryDbName=A.queryDbName)
|
|
666
668
|
Plugin_Helpers.queryFieldNamesRegistry->Dict.set(A.queryDbName, qn)
|
|
669
|
+
A.schedulesDbName->Option.forEach(queryDbName =>
|
|
670
|
+
Plugin_Helpers.queryFieldNamesRegistry->Dict.set(
|
|
671
|
+
queryDbName,
|
|
672
|
+
Api_Naming.queryFieldNamesForSliceQueryDb(~plugin=name, ~queryDbName),
|
|
673
|
+
)
|
|
674
|
+
)
|
|
667
675
|
})
|
|
668
676
|
|
|
669
677
|
outboundTranslationSlices->Array.forEach((module(O: OutboundTranslationSlice.T)) => {
|
|
@@ -1144,6 +1152,21 @@ module Make = (
|
|
|
1144
1152
|
}
|
|
1145
1153
|
})
|
|
1146
1154
|
|
|
1155
|
+
// A scheduled slice's schedules: when it runs, and who set it.
|
|
1156
|
+
let scheduleEntries = automationSlices->Array.filterMap((module(A: AutomationSlice.T)) =>
|
|
1157
|
+
A.schedulesDbName->Option.map(queryDbName => {
|
|
1158
|
+
let qn = Api_Naming.queryFieldNamesForSliceQueryDb(~plugin=name, ~queryDbName)
|
|
1159
|
+
{
|
|
1160
|
+
ReventlessInfra.Api.singleFieldName: qn.singleFieldName,
|
|
1161
|
+
listFieldName: qn.listFieldName,
|
|
1162
|
+
returnTypeName: qn.returnTypeName,
|
|
1163
|
+
stateSchema: AutomationSlice_Schedules.rowSchema->S.castToUnknown,
|
|
1164
|
+
authorization: None,
|
|
1165
|
+
connectionSpec: true,
|
|
1166
|
+
}
|
|
1167
|
+
})
|
|
1168
|
+
)
|
|
1169
|
+
|
|
1147
1170
|
let outboundEntries =
|
|
1148
1171
|
outboundTranslationSlices->Array.map((module(O: OutboundTranslationSlice.T)) => {
|
|
1149
1172
|
let qn = Api_Naming.queryFieldNamesForSliceQueryDb(
|
|
@@ -1234,6 +1257,7 @@ module Make = (
|
|
|
1234
1257
|
mutationEntries: Array.concat(mutationEntriesFromSlices, mutationEntriesFromInboundSlices),
|
|
1235
1258
|
queryEntries: stateViewEntries
|
|
1236
1259
|
->Array.concat(automationEntries)
|
|
1260
|
+
->Array.concat(scheduleEntries)
|
|
1237
1261
|
->Array.concat(outboundEntries)
|
|
1238
1262
|
->Array.concat(inboundEntries),
|
|
1239
1263
|
eventLogEntries: if allProducedSchemas->Array.length > 0 {
|
|
@@ -8,6 +8,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
8
8
|
import * as Effect from "effect/Effect";
|
|
9
9
|
import * as Pulumi from "@pulumi/pulumi";
|
|
10
10
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
11
|
+
import * as Clock$Reventless from "@reventlessdev/reventless-spec/src/components/Clock.res.mjs";
|
|
11
12
|
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
12
13
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
13
14
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
@@ -25,6 +26,7 @@ import * as Plugin_Structure$ReventlessCore from "../../plugin/component/Plugin_
|
|
|
25
26
|
import * as DcbEventLog_Builder$ReventlessCore from "../DcbEventLog/DcbEventLog_Builder.res.mjs";
|
|
26
27
|
import * as CommandTopic_Builder$ReventlessCore from "../CommandTopic/CommandTopic_Builder.res.mjs";
|
|
27
28
|
import * as AutomationSlice_Callback$ReventlessCore from "../AutomationSlice/AutomationSlice_Callback.res.mjs";
|
|
29
|
+
import * as AutomationSlice_Schedules$ReventlessCore from "../AutomationSlice/AutomationSlice_Schedules.res.mjs";
|
|
28
30
|
import * as CommandGenerator_Callback$ReventlessCore from "../CommandGenerator/CommandGenerator_Callback.res.mjs";
|
|
29
31
|
import * as InboundTranslationSlice_Callback$ReventlessCore from "../InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs";
|
|
30
32
|
import * as OutboundTranslationSlice_Callback$ReventlessCore from "../OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs";
|
|
@@ -150,10 +152,16 @@ function Make(DcbEventLogStorage) {
|
|
|
150
152
|
]).concat(stateViewSlices.map(V => [
|
|
151
153
|
V.Spec.name,
|
|
152
154
|
V.Spec.consumedEventSchema
|
|
153
|
-
])).concat(automationSlices.flatMap(A => A.Automation.mappings
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
])).concat(automationSlices.flatMap(A => Stdlib_Array.filterMap(A.Automation.mappings, M => {
|
|
156
|
+
if (M.sourceName === Clock$Reventless.name) {
|
|
157
|
+
return;
|
|
158
|
+
} else {
|
|
159
|
+
return [
|
|
160
|
+
A.Spec.name,
|
|
161
|
+
M.sourceEventSchema
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
}))).concat(outboundTranslationSlices.map(O => [
|
|
157
165
|
O.Spec.name,
|
|
158
166
|
O.Spec.consumedEventSchema
|
|
159
167
|
]));
|
|
@@ -352,6 +360,9 @@ function Make(DcbEventLogStorage) {
|
|
|
352
360
|
automationSlices.forEach(A => {
|
|
353
361
|
let qn = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, A.queryDbName, undefined);
|
|
354
362
|
Plugin_Helpers$ReventlessCore.queryFieldNamesRegistry[A.queryDbName] = qn;
|
|
363
|
+
Stdlib_Option.forEach(A.schedulesDbName, queryDbName => {
|
|
364
|
+
Plugin_Helpers$ReventlessCore.queryFieldNamesRegistry[queryDbName] = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, queryDbName, undefined);
|
|
365
|
+
});
|
|
355
366
|
});
|
|
356
367
|
outboundTranslationSlices.forEach(O => {
|
|
357
368
|
let qn = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, O.queryDbName, undefined);
|
|
@@ -612,6 +623,17 @@ function Make(DcbEventLogStorage) {
|
|
|
612
623
|
connectionSpec: true
|
|
613
624
|
};
|
|
614
625
|
});
|
|
626
|
+
let scheduleEntries = Stdlib_Array.filterMap(automationSlices, A => Stdlib_Option.map(A.schedulesDbName, queryDbName => {
|
|
627
|
+
let qn = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, queryDbName, undefined);
|
|
628
|
+
return {
|
|
629
|
+
singleFieldName: qn.singleFieldName,
|
|
630
|
+
listFieldName: qn.listFieldName,
|
|
631
|
+
returnTypeName: qn.returnTypeName,
|
|
632
|
+
stateSchema: AutomationSlice_Schedules$ReventlessCore.rowSchema,
|
|
633
|
+
authorization: undefined,
|
|
634
|
+
connectionSpec: true
|
|
635
|
+
};
|
|
636
|
+
}));
|
|
615
637
|
let outboundEntries = outboundTranslationSlices.map(O => {
|
|
616
638
|
let qn = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, O.queryDbName, undefined);
|
|
617
639
|
return {
|
|
@@ -655,7 +677,7 @@ function Make(DcbEventLogStorage) {
|
|
|
655
677
|
dcbPublishJsons: publishJsons,
|
|
656
678
|
dcbCommandTopicQueueUrl: dcbCommandTopicQueueUrl,
|
|
657
679
|
mutationEntries: mutationEntriesFromSlices.concat(mutationEntriesFromInboundSlices),
|
|
658
|
-
queryEntries: stateViewEntries.concat(automationEntries).concat(outboundEntries).concat(inboundEntries),
|
|
680
|
+
queryEntries: stateViewEntries.concat(automationEntries).concat(scheduleEntries).concat(outboundEntries).concat(inboundEntries),
|
|
659
681
|
eventLogEntries: allProducedSchemas.length !== 0 ? [{
|
|
660
682
|
busKey: name + "DcbEventLog",
|
|
661
683
|
displayName: name,
|
|
@@ -382,7 +382,7 @@ module Make = (
|
|
|
382
382
|
// and idResolver paths). Slice output dicts are keyed by Spec.name; the
|
|
383
383
|
// queryDb name appends a suffix per slice kind:
|
|
384
384
|
// StateViewSlice — no suffix
|
|
385
|
-
// AutomationSlice — "Todo"
|
|
385
|
+
// AutomationSlice — "Todo", and "Schedule" when it maps the Clock
|
|
386
386
|
// OutboundTranslationSlice — "Todo"
|
|
387
387
|
// InboundTranslationSlice — "Audit"
|
|
388
388
|
dcbResult.stateViewSlicesOutputs
|
|
@@ -393,7 +393,10 @@ module Make = (
|
|
|
393
393
|
->Array.forEach(((k, v)) => allQueryDbs->Dict.set(k ++ "Audit", v.queryDb))
|
|
394
394
|
dcbResult.automationSlicesOutputs
|
|
395
395
|
->Dict.toArray
|
|
396
|
-
->Array.forEach(((k, v)) =>
|
|
396
|
+
->Array.forEach(((k, v)) => {
|
|
397
|
+
allQueryDbs->Dict.set(k ++ "Todo", v.queryDb)
|
|
398
|
+
v.schedulesDb->Option.forEach(db => allQueryDbs->Dict.set(k ++ "Schedule", db))
|
|
399
|
+
})
|
|
397
400
|
dcbResult.outboundTranslationSlicesOutputs
|
|
398
401
|
->Dict.toArray
|
|
399
402
|
->Array.forEach(((k, v)) => allQueryDbs->Dict.set(k ++ "Todo", v.queryDb))
|
|
@@ -466,9 +469,13 @@ module Make = (
|
|
|
466
469
|
let extractEventTypes = schema => Reventless.DcbTag.extractVariantNames(schema)
|
|
467
470
|
let routingSchemas: Dict.t<Plugin_Helpers.pluginDeployedSchema> = Dict.make()
|
|
468
471
|
automationSlices->Array.forEach((module(As: ReventlessInfra.AutomationSlice.T)) => {
|
|
469
|
-
// Union of source-event variants across every per-source mapping.
|
|
472
|
+
// Union of source-event variants across every per-source mapping. The
|
|
473
|
+
// Clock's tick is no event of the plugin's; its schedule says when it comes.
|
|
470
474
|
let consumedEventTypes =
|
|
471
475
|
As.Automation.mappings
|
|
476
|
+
->Array.filter((module(M: As.Automation.Mapping)) =>
|
|
477
|
+
M.sourceName != Reventless.Clock.name
|
|
478
|
+
)
|
|
472
479
|
->Array.flatMap((module(M: As.Automation.Mapping)) =>
|
|
473
480
|
extractEventTypes(M.sourceEventSchema->S.castToUnknown)
|
|
474
481
|
)
|
|
@@ -6,6 +6,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
6
6
|
import * as Pulumi from "@pulumi/pulumi";
|
|
7
7
|
import * as Belt_SetString from "@rescript/runtime/lib/es6/Belt_SetString.js";
|
|
8
8
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
9
|
+
import * as Clock$Reventless from "@reventlessdev/reventless-spec/src/components/Clock.res.mjs";
|
|
9
10
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
10
11
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
11
12
|
import * as Plugin$Reventless from "@reventlessdev/reventless-spec/src/components/Plugin.res.mjs";
|
|
@@ -284,7 +285,12 @@ function Make(Spec) {
|
|
|
284
285
|
allQueryDbs[param[0] + "Audit"] = param[1].queryDb;
|
|
285
286
|
});
|
|
286
287
|
Object.entries(dcbResult.automationSlicesOutputs).forEach(param => {
|
|
287
|
-
|
|
288
|
+
let v = param[1];
|
|
289
|
+
let k = param[0];
|
|
290
|
+
allQueryDbs[k + "Todo"] = v.queryDb;
|
|
291
|
+
Stdlib_Option.forEach(v.schedulesDb, db => {
|
|
292
|
+
allQueryDbs[k + "Schedule"] = db;
|
|
293
|
+
});
|
|
288
294
|
});
|
|
289
295
|
Object.entries(dcbResult.outboundTranslationSlicesOutputs).forEach(param => {
|
|
290
296
|
allQueryDbs[param[0] + "Todo"] = param[1].queryDb;
|
|
@@ -348,7 +354,7 @@ function Make(Spec) {
|
|
|
348
354
|
});
|
|
349
355
|
let routingSchemas = {};
|
|
350
356
|
automationSlices.forEach(As => {
|
|
351
|
-
let consumedEventTypes = Belt_SetString.toArray(Belt_SetString.fromArray(As.Automation.mappings.flatMap(M => DcbTag$Reventless.extractVariantNames(M.sourceEventSchema))));
|
|
357
|
+
let consumedEventTypes = Belt_SetString.toArray(Belt_SetString.fromArray(As.Automation.mappings.filter(M => M.sourceName !== Clock$Reventless.name).flatMap(M => DcbTag$Reventless.extractVariantNames(M.sourceEventSchema))));
|
|
352
358
|
routingSchemas[As.Spec.name] = {
|
|
353
359
|
consumedEventTypes: consumedEventTypes,
|
|
354
360
|
producedCommandTypes: DcbTag$Reventless.extractAllVariantNames(As.Spec.commandSchema),
|
|
@@ -1775,6 +1775,8 @@ let make = (
|
|
|
1775
1775
|
// contributes that one source's variants.
|
|
1776
1776
|
let allConsumedVariants =
|
|
1777
1777
|
AS.Automation.mappings
|
|
1778
|
+
// The Clock's tick is no event of the plugin's; `schedule` says when it comes.
|
|
1779
|
+
->Array.filter((module(M: AS.Automation.Mapping)) => M.sourceName != Reventless.Clock.name)
|
|
1778
1780
|
->Array.flatMap((module(M: AS.Automation.Mapping)) =>
|
|
1779
1781
|
eventVariantNames(M.sourceEventSchema->S.castToUnknown)
|
|
1780
1782
|
)
|
|
@@ -1788,6 +1790,11 @@ let make = (
|
|
|
1788
1790
|
producedCommandTypes: qualify(~prefix=name, commandVariantNames(AS.Spec.commandSchema)),
|
|
1789
1791
|
targetName: AS.Spec.targetName,
|
|
1790
1792
|
chapter: chapterOf(AS.Spec.name),
|
|
1793
|
+
schedule: ?(
|
|
1794
|
+
AS.Spec.schedule->Option.map(time =>
|
|
1795
|
+
time->Reventless.Util_Sury.toJson(Reventless.Schedule.timeSchema)->JSON.stringify
|
|
1796
|
+
)
|
|
1797
|
+
),
|
|
1791
1798
|
}: Reventless.Plugin.automationSliceDef
|
|
1792
1799
|
)
|
|
1793
1800
|
})
|
|
@@ -6,12 +6,14 @@ import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
|
6
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
7
|
import * as Belt_SetString from "@rescript/runtime/lib/es6/Belt_SetString.js";
|
|
8
8
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
9
|
+
import * as Clock$Reventless from "@reventlessdev/reventless-spec/src/components/Clock.res.mjs";
|
|
9
10
|
import * as Owner$Reventless from "@reventlessdev/reventless-spec/src/components/Owner.res.mjs";
|
|
10
11
|
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
11
12
|
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
12
13
|
import * as Trait$Reventless from "@reventlessdev/reventless-spec/src/types/Trait.res.mjs";
|
|
13
14
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
14
15
|
import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
|
|
16
|
+
import * as Schedule$Reventless from "@reventlessdev/reventless-spec/src/types/Schedule.res.mjs";
|
|
15
17
|
import * as Semantic$Reventless from "@reventlessdev/reventless-spec/src/semantic/Semantic.res.mjs";
|
|
16
18
|
import * as Lifecycle$Reventless from "@reventlessdev/reventless-spec/src/types/Lifecycle.res.mjs";
|
|
17
19
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
@@ -1252,13 +1254,14 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
1252
1254
|
};
|
|
1253
1255
|
});
|
|
1254
1256
|
let automationSliceDefs = automationSlices.map(AS => {
|
|
1255
|
-
let allConsumedVariants = Belt_SetString.toArray(Belt_SetString.fromArray(AS.Automation.mappings.flatMap(M => DcbTag$Reventless.extractVariantNames(M.sourceEventSchema))));
|
|
1257
|
+
let allConsumedVariants = Belt_SetString.toArray(Belt_SetString.fromArray(AS.Automation.mappings.filter(M => M.sourceName !== Clock$Reventless.name).flatMap(M => DcbTag$Reventless.extractVariantNames(M.sourceEventSchema))));
|
|
1256
1258
|
return {
|
|
1257
1259
|
name: AS.Spec.name,
|
|
1258
1260
|
consumedEventTypes: qualify(name, allConsumedVariants),
|
|
1259
1261
|
producedCommandTypes: qualify(name, DcbTag$Reventless.extractAllVariantNames(AS.Spec.commandSchema)),
|
|
1260
1262
|
targetName: AS.Spec.targetName,
|
|
1261
|
-
chapter: componentChapters[AS.Spec.name]
|
|
1263
|
+
chapter: componentChapters[AS.Spec.name],
|
|
1264
|
+
schedule: Stdlib_Option.map(AS.Spec.schedule, time => JSON.stringify(Util_Sury$Reventless.toJson(time, Schedule$Reventless.timeSchema)))
|
|
1262
1265
|
};
|
|
1263
1266
|
});
|
|
1264
1267
|
let outboundTranslationSliceDefs = outboundTranslationSlices.map(OTS => ({
|
|
@@ -111,7 +111,7 @@ module Make = (Spec: Spec) => {
|
|
|
111
111
|
| PluginExtensionPointSpec.CreateDisconnectSchedule(id, timeout) =>
|
|
112
112
|
await createSchedule({
|
|
113
113
|
name: id->disconnectScheduleName,
|
|
114
|
-
|
|
114
|
+
time: timeout->ScheduleOps.minutesFromNow,
|
|
115
115
|
payload: {
|
|
116
116
|
Message.id,
|
|
117
117
|
meta: Message.generateMeta(~service=PluginExtensionPointSpec.name, ~user="Scheduler"),
|
|
@@ -108,7 +108,7 @@ function Make(Spec) {
|
|
|
108
108
|
let id = directive._0;
|
|
109
109
|
return await createSchedule({
|
|
110
110
|
name: disconnectScheduleName(id),
|
|
111
|
-
|
|
111
|
+
time: ScheduleOps$ReventlessCore.minutesFromNow(directive._1),
|
|
112
112
|
payload: JSON.stringify(Message$ReventlessCore.encodeCommand$p({
|
|
113
113
|
id: id,
|
|
114
114
|
meta: Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name, undefined, "Scheduler", undefined, undefined, undefined, undefined, undefined),
|
package/src/util/ScheduleOps.res
CHANGED
|
@@ -1,63 +1,9 @@
|
|
|
1
1
|
open Reventless.Schedule
|
|
2
2
|
|
|
3
|
-
module DateCalc = {
|
|
4
|
-
/*** Immutable functions to calculate new Dates without mutation the arguments */
|
|
5
|
-
@new
|
|
6
|
-
external dateFromDate: Date.t => Date.t = "Date"
|
|
7
|
-
|
|
8
|
-
let addMinutes: (Date.t, int) => Date.t = (date, minutes) => {
|
|
9
|
-
let result = date->dateFromDate
|
|
10
|
-
result->Date.setUTCMinutes(result->Date.getUTCMinutes + minutes)
|
|
11
|
-
result
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let addDays: (Date.t, int) => Date.t = (date, days) => {
|
|
15
|
-
let result = date->dateFromDate
|
|
16
|
-
result->Date.setUTCDate(result->Date.getUTCDate + days)
|
|
17
|
-
result
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
3
|
let forChannel = (~name, ~channelId, ~resourceNaming: ReventlessInfra.ResourceNaming.operations) =>
|
|
22
4
|
name->resourceNaming.validateName ++ ("-" ++ channelId->String.split("-")->Array.getUnsafe(1))
|
|
23
5
|
|
|
24
|
-
let minutesFromNow = minutes => {
|
|
25
|
-
let m = Date.make()->DateCalc.addMinutes(minutes)
|
|
26
|
-
Single(
|
|
27
|
-
m->Date.getUTCFullYear,
|
|
28
|
-
m->Date.getUTCMonth + 1,
|
|
29
|
-
m->Date.getUTCDate,
|
|
30
|
-
m->Date.getUTCHours,
|
|
31
|
-
m->Date.getUTCMinutes,
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let nextTime = (h: hour, m: minute) => {
|
|
36
|
-
let now = Date.make()
|
|
37
|
-
let today = {
|
|
38
|
-
let epoch = Date.make()
|
|
39
|
-
epoch->Date.setUTCHours(h)
|
|
40
|
-
epoch->Date.setUTCMinutes(m)
|
|
41
|
-
epoch->Date.setUTCSeconds(0)
|
|
42
|
-
epoch
|
|
43
|
-
}
|
|
44
|
-
let tomorrow = today->DateCalc.addDays(1)
|
|
45
|
-
today < now
|
|
46
|
-
? Single(
|
|
47
|
-
tomorrow->Date.getUTCFullYear,
|
|
48
|
-
tomorrow->Date.getUTCMonth + 1,
|
|
49
|
-
tomorrow->Date.getUTCDate,
|
|
50
|
-
tomorrow->Date.getUTCHours,
|
|
51
|
-
tomorrow->Date.getUTCMinutes,
|
|
52
|
-
)
|
|
53
|
-
: Single(
|
|
54
|
-
today->Date.getUTCFullYear,
|
|
55
|
-
today->Date.getUTCMonth + 1,
|
|
56
|
-
today->Date.getUTCDate,
|
|
57
|
-
today->Date.getUTCHours,
|
|
58
|
-
today->Date.getUTCMinutes,
|
|
59
|
-
)
|
|
60
|
-
}
|
|
6
|
+
let minutesFromNow = minutes => Once({moment: After(Minutes(minutes))})
|
|
61
7
|
|
|
62
8
|
exception ScheduleNotCreated(schedule)
|
|
63
9
|
exception ScheduleNotDeleted(string)
|
|
@@ -6,72 +6,27 @@ import * as Exit$1 from "effect/Exit";
|
|
|
6
6
|
import * as Cause from "effect/Cause";
|
|
7
7
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
8
8
|
import * as Effect$1 from "effect/Effect";
|
|
9
|
-
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
10
9
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
11
10
|
import * as Util_Error$ReventlessCore from "./Util_Error.res.mjs";
|
|
12
11
|
import * as EffectLogger$ReventlessCore from "./EffectLogger.res.mjs";
|
|
13
12
|
|
|
14
|
-
function addMinutes(date, minutes) {
|
|
15
|
-
let result = new Date(date);
|
|
16
|
-
result.setUTCMinutes(result.getUTCMinutes() + minutes | 0);
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function addDays(date, days) {
|
|
21
|
-
let result = new Date(date);
|
|
22
|
-
result.setUTCDate(result.getUTCDate() + days | 0);
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let DateCalc = {
|
|
27
|
-
addMinutes: addMinutes,
|
|
28
|
-
addDays: addDays
|
|
29
|
-
};
|
|
30
|
-
|
|
31
13
|
function forChannel(name, channelId, resourceNaming) {
|
|
32
14
|
return resourceNaming.validateName(name) + ("-" + channelId.split("-")[1]);
|
|
33
15
|
}
|
|
34
16
|
|
|
35
17
|
function minutesFromNow(minutes) {
|
|
36
|
-
let m = addMinutes(new Date(), minutes);
|
|
37
18
|
return {
|
|
38
|
-
TAG: "
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
19
|
+
TAG: "Once",
|
|
20
|
+
moment: {
|
|
21
|
+
TAG: "After",
|
|
22
|
+
_0: {
|
|
23
|
+
TAG: "Minutes",
|
|
24
|
+
_0: minutes
|
|
25
|
+
}
|
|
26
|
+
}
|
|
44
27
|
};
|
|
45
28
|
}
|
|
46
29
|
|
|
47
|
-
function nextTime(h, m) {
|
|
48
|
-
let now = new Date();
|
|
49
|
-
let epoch = new Date();
|
|
50
|
-
epoch.setUTCHours(h);
|
|
51
|
-
epoch.setUTCMinutes(m);
|
|
52
|
-
epoch.setUTCSeconds(0);
|
|
53
|
-
let tomorrow = addDays(epoch, 1);
|
|
54
|
-
if (Primitive_object.lessthan(epoch, now)) {
|
|
55
|
-
return {
|
|
56
|
-
TAG: "Single",
|
|
57
|
-
_0: tomorrow.getUTCFullYear(),
|
|
58
|
-
_1: tomorrow.getUTCMonth() + 1 | 0,
|
|
59
|
-
_2: tomorrow.getUTCDate(),
|
|
60
|
-
_3: tomorrow.getUTCHours(),
|
|
61
|
-
_4: tomorrow.getUTCMinutes()
|
|
62
|
-
};
|
|
63
|
-
} else {
|
|
64
|
-
return {
|
|
65
|
-
TAG: "Single",
|
|
66
|
-
_0: epoch.getUTCFullYear(),
|
|
67
|
-
_1: epoch.getUTCMonth() + 1 | 0,
|
|
68
|
-
_2: epoch.getUTCDate(),
|
|
69
|
-
_3: epoch.getUTCHours(),
|
|
70
|
-
_4: epoch.getUTCMinutes()
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
30
|
let ScheduleNotCreated = /* @__PURE__ */Primitive_exceptions.create("ScheduleOps-ReventlessCore.ScheduleNotCreated");
|
|
76
31
|
|
|
77
32
|
let ScheduleNotDeleted = /* @__PURE__ */Primitive_exceptions.create("ScheduleOps-ReventlessCore.ScheduleNotDeleted");
|
|
@@ -79,11 +34,11 @@ let ScheduleNotDeleted = /* @__PURE__ */Primitive_exceptions.create("ScheduleOps
|
|
|
79
34
|
function create(scheduler, channelResources, resourceNaming) {
|
|
80
35
|
return async schedule => {
|
|
81
36
|
let name = resourceNaming.validateName(schedule.name);
|
|
82
|
-
let
|
|
37
|
+
let schedule_time = schedule.time;
|
|
83
38
|
let schedule_payload = schedule.payload;
|
|
84
39
|
let schedule$1 = {
|
|
85
40
|
name: name,
|
|
86
|
-
|
|
41
|
+
time: schedule_time,
|
|
87
42
|
payload: schedule_payload
|
|
88
43
|
};
|
|
89
44
|
let createSchedule = scheduler.createSchedule;
|
|
@@ -120,10 +75,8 @@ function $$delete(scheduler, channelResources, resourceNaming) {
|
|
|
120
75
|
}
|
|
121
76
|
|
|
122
77
|
export {
|
|
123
|
-
DateCalc,
|
|
124
78
|
forChannel,
|
|
125
79
|
minutesFromNow,
|
|
126
|
-
nextTime,
|
|
127
80
|
ScheduleNotCreated,
|
|
128
81
|
ScheduleNotDeleted,
|
|
129
82
|
create,
|